StatefulSet of kubernetes commonly used controller

StatefulSet of kubernetes commonly used controller

1. Introduction

The unequal relationship between the instances and the applications where the instances have dependencies on external data are called "stateful applications".
The so-called unequal relationship between instances means that for distributed applications, there are often relatively large dependencies between each instance and each application. For example, an application must be started before other applications, otherwise other applications will not be started.
The most significant application that has a dependency on external data is the database application. For database applications, we need to store its data persistently. If it is a stateless application, restarting the data in the database and the application will lose contact, which is obviously a violation Our original intention was not to put it into production.

Therefore, in order to solve the effective support of stateful applications in Kubernetes, Kubernetes uses StatefulSet to orchestrate and manage stateful applications.
StatefulSet is similar to ReplicaSet. The difference is that it can control the startup sequence of Pods, and it sets a unique identifier for each Pod. It has the following functions:

  • Stable, unique network identifier

  • Stable, persistent storage

  • Orderly, elegant deployment and scaling

  • Orderly, automatic rolling update

The design of StatefulSet is easy to understand. It abstracts the real world into the following two situations:
(1) Topological state. This means that there is an asymmetric relationship between applications. Applications must be started in a certain order. Even if the application is restarted, it must be restarted in the specified order, and its network identification must be the same as the original after restart, so that the original access can be guaranteed The user can access the new Pod through the same method;
(2), storage state. This means that the application is bound to stored data, no matter when, no matter what the situation, for the application, as long as the data in the storage does not change, the data read should be the same;

So the core function of StatefulSet is to record the state of the Pod in a certain way, and then restore its state in some way when the Pod is re-created.

二、Headless Service

Before introducing StatefulSet, let's first understand what Headless Service is.
We know that in Kubernetes, Service is a way to provide external access to a group of Pods. Usually, we use Service to access Pod in the following two ways:
(1) Through Cluster IP, this Cluster IP is equivalent to VIP. When we visit this IP, the request will be forwarded to the backend Pod;
(2) Through DNS method, in this way, you must first ensure that there is DNS service in the Kubernetes cluster. At this time, as long as we access "my-service.my-namespace.svc,cluster.local", we can access the backend Pod proxied by the Service named my-service;

For the second method, there are the following two processing methods:
(1) Normal Service, that is, resolve the domain name, and get the Cluster IP, and then access according to method one;
(2), Headless Service, that is, resolve the domain name to get Is the IP address of a Pod in the backend, so that it can be accessed directly;

For the second processing method, we can see that there is no need for Cluster IP, but the IP address of the backend Pod is directly resolved through the domain name for access.
The following is a simple YAML file definition of Headless Service:

apiVersion: v1

kind: Service

metadata:

  name: nginx

  labels:

    app: nginx

spec:

  ports:

  - port: 80

    name: web

  clusterIP: None

  selector:

    app: nginx

It can be seen from the above YAML file that there is not much difference from our ordinary Service definition. The only difference is that the clusterIP is set to None, that is, no cluster is needed. We create this Service through kubectl apply -f, and then check the service's Cluster IP is None.
StatefulSet of kubernetes commonly used controller

The Service created in this way is a Headless Service, it does not have a VIP, so it will expose the Pod it proxied in the form of DNS records.

Three, use StatefulSet

Create the PV before creating the StatefulSet, as follows:

apiVersion: v1

kind: PersistentVolume

metadata:

  name: pv01

  labels:

    release: stable

spec:

  capacity:

    storage: 1Gi

  accessModes:

  - ReadWriteOnce

  persistentVolumeReclaimPolicy: Recycle

  hostPath:

    path: /tmp/data

---

apiVersion: v1

kind: PersistentVolume

metadata:

  name: pv02

  labels:

    release: stable

spec:

  capacity:

    storage: 1Gi

  accessModes:

  - ReadWriteOnce

  persistentVolumeReclaimPolicy: Recycle

  hostPath:

    path: /tmp/data

Then execute kubectl apply -f to start PV, as follows:

[root@master statefulset]# kubectl apply -f pv.yaml

persistentvolume/pv01 created

persistentvolume/pv02 created

[root@master statefulset]# kubectl get pv

NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE

pv01   1Gi        RWO            Recycle          Available                                   10s

pv02   1Gi        RWO            Recycle          Available                                   9s

You can see that the states of the two PVs are both available, and then write the YAML file of the StatefulSet:

apiVersion: v1

kind: Service

metadata:

  name: nginx

spec:

  ports:

  - port: 80

    name: web

  clusterIP: None

  selector:

    app: nginx

    role: stateful

---

apiVersion: apps/v1

kind: StatefulSet

metadata:

  name: web

spec:

  serviceName: "nginx"

  replicas: 2

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

        role: stateful

    spec:

      containers:

      - name: nginx

        image: cnych/nginx-slim:0.8

        ports:

        - containerPort: 80

          name: web

        volumeMounts:

        - name: www

          mountPath: /usr/share/nginx/html

  volumeClaimTemplates:

  - metadata:

      name: www

    spec:

      accessModes: [ "ReadWriteOnce" ]

      resources:

        requests:

          storage: 1Gi

Note that the above YAML file associated with volumeMounts is a new attribute: volumeClaimTemplates, this attribute will automatically declare a pvc object and pv for management, and serviceName: "nginx" means that the headless of nginx is used when the control loop is executed. Service to save the resolvable identity of the Pod.

Then here we open two terminal windows. In the first terminal, use kubectl get to view the creation of the Pods of the StatefulSet.

$ kubectl get pods -w -l role=stateful

In another terminal, use kubectl create to create the Headless Service and StatefulSet defined in statefulset-demo.yaml.

$ kubectl create -f statefulset-demo.yaml

service "nginx" created

statefulset.apps "web" created

Then we observe the startup sequence of the Pod:

[root@master ~]# kubectl get pods -w -l role=stateful

web-0   0/1   Pending   0     0s

web-0   0/1   Pending   0     0s

web-0   0/1   ContainerCreating   0     0s

web-0   1/1   Running             0     3m12s

web-1   0/1   Pending             0     0s

web-1   0/1   Pending             0     0s

web-1   0/1   Pending             0     1s

web-1   0/1   ContainerCreating   0     1s

web-1   1/1   Running             0     5s

Through the above creation process, we can see that StatefulSet numbers the Pods it manages. Its naming rule is [statefulset-name]-[index], and its index starts from 0, which is the same as each Pod instance of StatefulSet. One correspondence, never repeat. More importantly, the Pod creation process is sequential. As above, web-1 enters the pending state after web-0 enters the running state.

We use the command to view the results of its creation:

[root@master statefulset]# kubectl get statefulset web

NAME   READY   AGE

web    2/2     17m

[root@master statefulset]# kubectl get pods -l role=stateful

NAME    READY   STATUS    RESTARTS   AGE

web-0   1/1     Running   0          17m

web-1   1/1     Running   0          14m

[root@master statefulset]# kubectl get svc nginx

NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

nginx   ClusterIP   None         <none>        80/TCP    17m

When both Pods enter the running state, you can view their respective network identities. We can view them through kubectl exec, as follows:

[root@master statefulset]# kubectl exec web-0 -- sh -c 'hostname'

web-0

[root@master statefulset]# kubectl exec web-1 -- sh -c 'hostname'

web-1

You can see that the hostname and pod name of the two pods are the same, and they are all assigned corresponding numbers. Next, we use DNS to access the Headless Service.
We first start a Pod with the following command:

kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh

Then use nslookup to parse the Headless Service corresponding to a Pod in this Pod:

kubectl run -i --tty --image centos dns-test --restart=Never --rm /bin/sh

sh-4.2# yum install bind-utils -y

sh-4.2# nslookup web-0.nginx

Server:        10.68.0.2

Address:    10.68.0.2#53

Name:    web-0.nginx.default.svc.cluster.local

Address: 172.20.2.63

sh-4.2# nslookup web-1.nginx

Server:        10.68.0.2

Address:    10.68.0.2#53

Name:    web-1.nginx.default.svc.cluster.local

Address: 172.20.2.64

From the analysis of the results of nslookup, when accessing web-0.nginx, the IP of the Pod web-0 is parsed, and the other is the same.
At this time, if we delete the two Pods, and then observe the process of restarting the Pod:

[root@master statefulset]# kubectl delete pod -l role=stateful

pod "web-0" deleted

pod "web-1" deleted

Then check the restart sequence as follows:

[root@master ~]# kubectl get pods -w -l role=stateful

NAME    READY   STATUS    RESTARTS   AGE

web-0   0/1     ContainerCreating   0          0s

web-0   1/1     Running             0          2s

web-1   0/1     Pending             0          0s

web-1   0/1     Pending             0          0s

web-1   0/1     ContainerCreating   0          0s

web-1   1/1     Running             0          2s

We can see that after we delete the Pod, its restart sequence is still restarted according to the original number, and its network identification remains the same as before.
Through this strict correspondence rule, StatefulSet guarantees the stability of the Pod's network identity. Through this method, the Pod's topological state can be fixed according to the Pod's name + number. In addition, Kubernetes also provides a fixed and unique access entry for each Pod, that is, the Pod's DNS record.

We can also check the binding of PV and PVC:

[root@master statefulset]# kubectl get pv

NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE

pv01   1Gi        RWO            Recycle          Bound    default/www-web-0                           129m

pv02   1Gi        RWO            Recycle          Bound    default/www-web-1                           129m

[root@master statefulset]# kubectl get pvc

NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE

www-web-0   Bound    pv01     1Gi        RWO                           124m

www-web-1   Bound    pv02     1Gi        RWO                           116m

Therefore, we sort out StatefulSet as follows:
(1), StatefulSet directly manages Pod. This is because the Pod instances in the StatefulSet are not exactly the same as the Pod instances in the ReplicaSet. They are slightly different. For example, the name and hostname of each Pod are different, and the way that the StatefulSet distinguishes these instances is to add the Pod Number;
(2), Kubernetes generates a record with the same number in the DNS server for this numbered Pod through the Headless Service. As long as the StatefulSet can ensure that the number of this Pod remains unchanged, the DNS record similar to web-0.nginx.default.svc.cluster.local in the Service will not change, and the Pod IP address resolved by this record will follow. It is automatically updated with Pod re-creation;
(3) StatefulSet can also allocate and create a PVC with the same number as the Pod for each Pod. In this way, Kubernetes can bind the corresponding PV to this PVC through the Persitent Volume mechanism, thereby ensuring that each Pod has an independent Volume. In this case, even if the Pod is deleted, its corresponding PVC and PV will still be retained, so when the Pod is recreated, Kubernetes will find the PVC with the same number for it, and mount the volume corresponding to the PVC. Get the previous data of the previous Volume;

Four, summary

One of the main functions of the StatefulSet controller is to number them when creating Pods using the Pod template, and complete the tasks in the order of the numbers. When the control loop of the StatefulSet finds that the actual state of the Pod is inconsistent with the expected state, it will also Operate the Pod in order.

Of course, StatefulSet also has other features. In actual projects, we still rarely go back and deploy our stateful services directly through StatefulSet, unless you can fully hold it yourself. For some specific services, we may use more Advanced Operators are deployed, such as etcd-operator, prometheus-operator, etc. These applications can manage stateful services very well, instead of just using a StatefulSet to deploy a Pod, because for stateful applications The most important thing is data recovery, failover and so on.

Finish

Guess you like

Origin blog.51cto.com/15080014/2654577