How to Deploy an NGINX Service in a Kubernetes Cluster

How to Deploy an NGINX Service in a Kubernetes Cluster

https://medium.com/aws-in-plain-english/how-to-deploy-an-nginx-service-in-a-kubernetes-cluster-2139ff565604
Photo by Growtika on Unsplash


Namespace

a namespace is a very important resource in the Kubernetes system. Its main function is to implement resource isolation for multiple environments or resource isolation for multiple tenants.

By default, all Pods in a Kubernetes cluster can access each other. However, in practice, you may not want two Pods to access each other. In this case, you can divide the two Pods into different namespaces. By allocating resources in the cluster to different namespaces, Kubernetes can form “groups” logically, making it easy for resources of different groups to be isolated and managed.

By using Kubernetes’ authorization mechanism, different namespaces can be handed over to different tenants for management, thus achieving resource isolation for multiple tenants. At this time, Kubernetes’ resource quota mechanism can also be combined to limit the resources that different tenants can use, such as CPU usage, memory usage, etc., to manage the available resources for tenants.

After the Kubernetes cluster is started, several namespaces are created by default:

Kubernetes cluster is started, and several namespaces are created. Illustration by author.

After the Kubernetes cluster is started, several namespaces are created by default:

[root@master ~]# kubectl get namespace
NAME STATUS AGE
default Active 45h # All objects that are not specified in the namespace are assigned to the default namespace
kube-node-lease Active 45h # Heartbeat maintenance between cluster nodes, introduced since v1.13
kube-public Active 45h # Resources under this namespace can be accessed by everyone (including unauthenticated users)
kube-system Active 45h # All resources created by the Kubernetes system are in this namespace

Let’s take a look at the specific operations of namespace resources:

View

# 1 View all namespaces
Command: kubectl get ns
[root@master ~]# kubectl get ns
NAME              STATUS   AGE
default           Active   45h
kube-node-lease   Active   45h
kube-public       Active   45h     
kube-system       Active   45h     

# 2 View a specific namespace
Command: kubectl get ns <namespace name>
[root@master ~]# kubectl get ns default
NAME      STATUS   AGE
default   Active   45h

# 3 Specify output format
Command: kubectl get ns <namespace name> -o <format>
Kubernetes supports many output formats, including wide, json, and yaml.
[root@master ~]# kubectl get ns default -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2020-04-05T04:44:16Z"
  name: default
  resourceVersion: "151"
  selfLink: /api/v1/namespaces/default
  uid: 7405f73a-e486-43d4-9db6-145f1409f090
spec:
  finalizers:
  - kubernetes
status:
  phase: Active
  
# 4 View namespace details
Command: kubectl describe ns <namespace name>
[root@master ~]# kubectl describe ns default
Name:         default
Labels:       <none>
Annotations:  <none>
Status:       Active  # Active namespaces are in use, while Terminating namespaces are being deleted.

# ResourceQuota limits resources for a namespace
# LimitRange limits resources for each component in a namespace
No resource quota.
No LimitRange resource.

Create

# Create namespace
[root@master ~]# kubectl create ns dev
namespace/dev created

Delete

# Delete namespace
[root@master ~]# kubectl delete ns dev
namespace "dev" deleted

Configuration method

To configure a namespace, a YAML file named ns-dev.yaml is created with the following contents:

apiVersion: v1
kind: Namespace
metadata:
  name: dev

To create the namespace, the following command is used:

kubectl create -f ns-dev.yaml

To delete the namespace, the following command is used:

kubectl delete -f ns-dev.yaml

Pod

A Pod is the smallest unit managed by the Kubernetes cluster. Programs must be deployed in containers, which must exist in Pods.

A Pod can be considered a container wrapper, and one or more containers can exist in a Pod.

A Pod can be considered a container wrapper, and one or more containers can exist in a Pod. Illustration by author.

After Kubernetes is started in the cluster, each component in the cluster runs in a Pod. You can use the following command to view them:

[root@master ~]# kubectl get pod -n kube-system
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6955765f44–68g6v 1/1 Running 0 2d1h
kube-system coredns-6955765f44-cs5r8 1/1 Running 0 2d1h
kube-system etcd-master 1/1 Running 0 2d1h
kube-system kube-apiserver-master 1/1 Running 0 2d1h
kube-system kube-controller-manager-master 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64–47r25 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64-ls5lh 1/1 Running 0 2d1h
kube-system kube-proxy-685tk 1/1 Running 0 2d1h
kube-system kube-proxy-87spt 1/1 Running 0 2d1h
kube-system kube-scheduler-master 1/1 Running 0 2d1h
~~~

To create and run a Pod

Kubernetes does not provide a command to run a Pod separately, but it is implemented through a Pod controller.

# Command format: kubectl run (Pod controller name) [parameter]
# --image specifies the image of the Pod
# --port specifies the port
# --namespace  specifies the namespace
[root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev 
deployment.apps/nginx created

View pod information

# View basic pod information
[root@master ~]# kubectl get pods -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff7956ff6-fg2db   1/1     Running   0          43s

# View detailed pod information
[root@master ~]# kubectl describe pod nginx-5ff7956ff6-fg2db -n dev
Name:         nginx-5ff7956ff6-fg2db
Namespace:    dev
Priority:     0
Node:         node1/192.168.109.101
Start Time:   Wed, 08 Apr 2020 09:29:24 +0800
Labels:       pod-template-hash=5ff7956ff6
              run=nginx
Annotations:  <none>
Status:       Running
IP:           10.244.1.23
IPs:
  IP:           10.244.1.23
Controlled By:  ReplicaSet/nginx-5ff7956ff6
Containers:
  nginx:
    Container ID:   docker://4c62b8c0648d2512380f4ffa5da2c99d16e05634979973449c98e9b829f6253c
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 08 Apr 2020 09:30:01 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-hwvvw (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-hwvvw:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-hwvvw
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned dev/nginx-5ff7956ff6-fg2db to node1
  Normal  Pulling    4m11s      kubelet, node1     Pulling image "nginx:1.17.1"
  Normal  Pulled     3m36s      kubelet, node1     Successfully pulled image "nginx:1.17.1"
  Normal  Created    3m36s      kubelet, node1     Created container nginx
  Normal  Started    3m36s      kubelet, node1     Started container nginx

Accessing a Pod

# Get the pod IP
[root@master ~]# kubectl get pods -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP             NODE    ... 
nginx-5ff7956ff6-fg2db   1/1     Running   0          190s   10.244.1.23   node1   ...

# Access the pod
[root@master ~]# curl http://10.244.1.23:80
<!DOCTYPE html>
<html>
<head>
 <title>Welcome to nginx!</title>
</head>
<body>
 <p><em>Thank you for using nginx.</em></p>
</body>
</html>

Deleting a Specified Pod

# Delete a specified pod
[root@master ~]# kubectl delete pod nginx-5ff7956ff6-fg2db -n dev
pod "nginx-5ff7956ff6-fg2db" deleted

# At this point, the pod deletion was successful, but if we check again, we will see a new pod created
[root@master ~]# kubectl get pods -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff7956ff6-jj4ng   1/1     Running   0          21s

# This is because the pod is created by a pod controller which monitors the pod status and rebuilds the pod once it detects that the pod has died.
# To delete the pod, we need to delete the pod controller.

# First, we need to check the pod controllers in the current namespace
[root@master ~]# kubectl get deploy -n  dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           9m7s

# Next, delete the pod controller
[root@master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted

# After a short while, check the pods again, and we will see that the pod has been deleted
[root@master ~]# kubectl get pods -n dev
No resources found in dev namespace.

Configuration Steps

Create a file named pod-nginx.yaml with the following contents:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:1.17.1
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

Then we can execute the corresponding create and delete commands:

​ Create: kubectl create -f pod-nginx.yaml

​ Delete: kubectl delete -f pod-nginx.yaml

Label

Label is an important concept in the Kubernetes system. Its purpose is to attach a tag to resources to distinguish and select them.

The characteristics of Label are:

  • A label is attached to various objects in the form of key/value pairs, such as Node, Pod, Service, etc.
  • A resource object can define any number of Labels, and the same Label can also be added to any number of resource objects.
  • Labels are usually determined when resource objects are defined, but they can also be dynamically added or deleted after the object is created.

Labels can be used to implement multi-dimensional grouping of resources, making it flexible and convenient to manage resource allocation, scheduling, configuration, deployment, and other management tasks.

Some commonly used Label examples:
Version label: “version”:”release”, “version”:”stable”……
Environment label: “environment”:”dev”, “environment”:”test”, “environment”:”pro”
Architecture label: “tier”:”frontend”, “tier”:”backend”

After the Label is defined, the Label Selector should also be considered for Label selection, that is:

  • Label is used to define the identity of a resource object
  • Label Selector is used to querying and filtering resource objects that have certain labels

There are currently two types of Label Selectors:

  • Equality-based Label Selector
  • name = slave: Selects all objects that contain the Label with key=”name” and value=”slave”
  • env != production: Selects all objects that contain the Label with key=”env” and value is not “production”
  • Set-based Label Selector
  • name in (master, slave): Selects all objects that contain the Label with key=”name” and value is “master” or “slave”
  • name not in (frontend): Selects all objects that contain the Label with key=”name” and value is not “frontend”

Multiple Label Selector conditions can be used, and they are combined using commas “,”. For example:

​ name=slave,env!=production

​ name not in (frontend),env!=production

Command Line

# Add label to the pod resource
[root@master ~]# kubectl label pod nginx-pod version=1.0 -n dev
pod/nginx-pod labeled

# Update label for the pod resource
[root@master ~]# kubectl label pod nginx-pod version=2.0 -n dev --overwrite
pod/nginx-pod labeled

# View the label
[root@master ~]# kubectl get pod nginx-pod  -n dev --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
nginx-pod   1/1     Running   0          10m   version=2.0

# Filter the label
[root@master ~]# kubectl get pod -n dev -l version=2.0  --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
nginx-pod   1/1     Running   0          17m   version=2.0
[root@master ~]# kubectl get pod -n dev -l version!=2.0 --show-labels
No resources found in dev namespace.

# Delete the label
[root@master ~]# kubectl label pod nginx-pod version- -n dev
pod/nginx-pod labeled

Configuration method

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels:
    version: "3.0" 
    env: "test"
spec:
  containers:
  - image: nginx:1.17.1
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

Then you can execute the corresponding update command: kubectl apply -f pod-nginx.yaml.

Deployment

In Kubernetes, the Pod is the smallest unit of control, but Kubernetes rarely directly controls Pods. Instead, Pod controllers are used to managing Pods, ensuring that the Pod resources meet the expected state. When Pod resources fail, the controller will attempt to restart or rebuild the Pod.

There are many types of Pod controllers in Kubernetes, but this chapter will only introduce one: Deployment.

Deployment and pod.Illustration by author.

Command Operation

# Command format: kubectl run deployment_name [arguments]
# --image specifies the image of the pod
# --port specifies the port
# --replicas specifies the number of pod replicas to create
# --namespace specifies the namespace
[root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
deployment.apps/nginx created

# View the created pods
[root@master ~]# kubectl get pods -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff7956ff6-6k8cb   1/1     Running   0          19s
nginx-5ff7956ff6-jxfjt   1/1     Running   0          19s
nginx-5ff7956ff6-v6jqw   1/1     Running   0          19s

# View deployment information
[root@master ~]# kubectl get deploy -n dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           2m42s

# UP-TO-DATE: number of replicas successfully updated
# AVAILABLE: number of available replicas
[root@master ~]# kubectl get deploy -n dev -o wide
NAME    READY UP-TO-DATE  AVAILABLE   AGE     CONTAINERS   IMAGES              SELECTOR
nginx   3/3     3         3           2m51s   nginx        nginx:1.17.1        run=nginx

# View deployment details
[root@master ~]# kubectl describe deploy nginx -n dev
Name:                   nginx
Namespace:              dev
CreationTimestamp:      Wed, 08 Apr 2020 11:14:14 +0800
Labels:                 run=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               run=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  run=nginx
  Containers:
   nginx:
    Image:        nginx:1.17.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-5ff7956ff6 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  5m43s  deployment-controller  Scaled up replicaset nginx-5ff7956ff6 to 3
  
# Delete
[root@master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted

Configuration Operations

Create a file named deploy-nginx.yaml with the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx:1.17.1
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP

Then, execute the following commands to create and delete the deployment:

  • Create: kubectl create -f deploy-nginx.yaml
  • Delete: kubectl delete -f deploy-nginx.yaml

Service

In Kubernetes, a Pod is the smallest unit of control. However, Kubernetes rarely controls Pods directly. Instead, it uses Pod controllers to manage the Pods and ensure that they meet the expected state. When a Pod’s resources fail, the controller will try to restart or rebuild the Pod.

In Kubernetes, there are many types of Pod controllers. In this section, we will only introduce one: Deployment.

Although each Pod is assigned a separate Pod IP, there are two problems:

  • Pod IP changes when the Pod is rebuilt.
  • Pod IP is a virtual IP that is only visible within the cluster, and cannot be accessed from outside.

This makes it difficult to access the service. Therefore, Kubernetes has designed the Service to solve this problem.

A Service can be seen as an access interface for a group of Pods of the same type to the outside world. With a Service, applications can easily achieve service discovery and load balancing.

A Service can be seen as an access interface for a group of Pods of the same type to the outside world. Illustration by author.

Operation 1: Creating a Service for Internal Cluster Access

# Expose Service
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed

# View Service
[root@master ~]# kubectl get svc svc-nginx -n dev -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE     SELECTOR
svc-nginx1   ClusterIP   10.109.179.231   <none>        80/TCP    3m51s   run=nginx

# A CLUSTER-IP is generated here, which is the IP address of the service. This address will not change during the service lifecycle
# The current POD corresponding to this service can be accessed through this IP
[root@master ~]# curl 10.109.179.231:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
.......
</body>
</html>

Operation 2: Creating a Service for External Cluster Access

# The type of the service created above is ClusterIP, and this IP address is only accessible within the cluster
# If you need to create a service that can also be accessed from outside the cluster, you need to modify the type to NodePort
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed

# At this point, a NodePort type of service appears, and there is a pair of Ports (80:31928/TC)
[root@master ~]# kubectl get svc svc-nginx-1  -n dev -o wide
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE    SELECTOR
svc-nginx2    NodePort    10.100.94.0      <none>        80:31928/TCP   9s     run=nginx

# Next, the service can be accessed through the node IP:31928 from outside the cluster
# For example, access the following address in a computer's browser
http://192.168.109.100:31928/

Deleting a Service

[root@master ~]# kubectl delete svc svc-nginx-1 -n dev                                   service "svc-nginx-1" deleted

Configuration Method

Create a svc-nginx.yaml file with the following content:

apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 10.109.179.231
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: ClusterIP

Then execute the corresponding creation and deletion commands:

Create: kubectl create -f svc-nginx.yaml

Delete: kubectl delete -f svc-nginx.yaml

Summary
With the basic operations of Namespace, Pod, Deployment, and Service resources, a simple deployment and access to a service can be achieved in the Kubernetes cluster. However, to make better use of Kubernetes, it is necessary to delve into the details and principles of these resources.


Report Page