The use of DaemonSet and StatefulSet
Today we will explain to you how to use another Pod
controller. We mainly explained Deployment
the use of this kind of object resources. Next, we will explain the controllers used in specific occasions: DaemonSet
and StatefulSet
.
Use of DaemonSets
From the name of the controller, we can see its usage: Daemon is used to deploy the daemon process, and is used to run a copy of the daemon process as a background process DaemonSet
in each Kubernetes
node. To put it bluntly, it is to deploy a daemon process on each node Pod
Copy, when a node joins Kubernetes
the cluster, Pod
it will be scheduled to run on the node. When the node can only be removed from the cluster, this node on the node Pod
will also be removed. Of course, if we delete DaemonSet
, all and this object The related ones Pods
will be deleted.
Under what circumstances do we need to use this business scenario? In fact, this scenario is relatively common, such as:
- A cluster storage daemon, e.g.
glusterd
toceph
be deployed on each node to provide persistent storage; - Node monitoring daemons, such as
Prometheus
monitoring clusters, can run a process on each nodenode-exporter
to collect information about monitoring nodes; - A log collection daemon, such as
fluentd
orlogstash
, runs on each node to collect logs for containers
One thing that needs to be specially explained here is the scheduling problem of DaemonSet
running Pod
. Under normal circumstances, Pod
which node to run on is Kubernetes
determined by the scheduler policy. However, the node DaemonSet
created by the controller Pod
has actually been determined in advance. ( Pod
specified at creation time .spec.nodeName
), so:
DaemonSet
It doesn't care about the fields of a nodeunshedulable
, which we will explain to you in the scheduling chapter later.DaemonSet
Can be createdPod
even if the scheduler has not been started, which is very important.
Below we directly use an example to demonstrate, deploying one on each node Nginx Pod
: (nginx-ds.yaml)
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: nginx-ds
labels:
k8s-app: nginx
spec:
selector:
matchLabels:
k8s-app: nginx
template:
metadata:
labels:
k8s-app: nginx
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- name: http
containerPort: 80
Then create it directly:
$ kubectl create -f nginx-ds.yaml
Then we can observe Pod
whether it is distributed to each node:
$ kubectl get nodes
$ kubectl get pods -o wide
Use of StatefulSets
Before learning StatefulSet
this kind of controller, we have to understand a concept: what is a stateful service? What is a stateless service?
-
Stateless Service (Stateless Service): The running instance of this service will not store locally the data that needs to be persisted, and the results of multiple instances responding to the same request are completely consistent, such as the instance we explained earlier, do
WordPress
we Multiple instances can be started at the same time, but the results we get from any instance are the same, right? Because the only data he needs to persist is stored inMySQL
the database, we can say thatWordPress
this application is a stateless service, butMySQL
the database is not, because he needs to persist the data locally. -
Stateful Service (Stateful Service): It is opposite to the above concept. The running instance of this service needs to store persistent data locally. For example, the above database, if you are running on node A now, its data will be stored
MySQL
in On node A, if you migrate the service to node B at this time, there will be no previous data, because he needs to restore the data in the corresponding data directory, and there is no data at this time.
Now everyone has a certain understanding of stateful and stateless. For example, our common WEB application session
maintains the user's login status. If we session
persist it to the node, then the application is a stateful service Yes, because I am now logged in and you have persisted my data to node A. The next time I log in, the request may be routed to node B, but there is no current data session
on node B at all, so it will session
It is considered as not logged in, which caused the results of my two requests to be inconsistent. So in general, for horizontal expansion, we will change this type of WEB application into a stateless service, how to change it? Is it enough to session
store the data in a public place, such as inside, for some client requests, we don't use it to keep the user status, and it is also possible to use it instead.redis
API
session
token
Stateless services can be well controlled by using our previous or stateful services. For stateful services, there are many more details to consider. One of the most difficult tasks for containerized applications is to design the deployment of stateful distributed components Deployment
. RC
Architecture. Since stateless components may not have predefined startup sequences, clustering requirements, point-to-point TCP connections, unique network identifiers, graceful startup and termination requirements, etc., they can be easily containerized. Systems such as databases, big data analysis systems, distributed key/value stores, and message brokers may have complex distributed architectures, and may use the above functions. To this end, resources Kubernetes
are introduced StatefulSet
to support this complex requirement.
StatefulSet
Similar to ReplicaSet
, but it can handle Pod
the startup sequence, Pod
setting a unique identifier for preserving the state of each, while having the following functions:
- Stable, unique network identifier
- Stable, persistent storage
- Orderly, graceful deployment and scaling
- Orderly, graceful deletion and termination
- Orderly, automatic rolling updates
Create a StatefulSet
Next, we will show you StatefulSet
how to use the object. Before we start, we will prepare two 1G storage volumes (PV). In the following courses, we will also explain in detail how to use PV and PVC. Let's not delve into it here: (pv001.yaml)
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
release: stable
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: /tmp/data
The other one only needs to change the name to pv002, and then create:
$ kubectl create -f pv001.yaml && kubectl create -f pv002.yaml
persistentvolume "pv001" created
persistentvolume "pv002" created
$ kubectl get pv
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWO Recycle Available 12s
pv002 1Gi RWO Recycle Available 11s
You can see that two PV objects have been created successfully, and the status is: Available.
Then we use it StatefulSet
to create an Nginx Pod. For this type of resource, we generally Headless Service
expose the service by creating a type of service, which will be clusterIP
set None
as a headless service: (statefulset-demo.yaml)
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
role: stateful
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
volumeMounts
Note that a new attribute is associated with the above YAML file : volumeClaimTemplates , which automatically declares a pvc object and pv for management:
Then here we open two terminal windows. In the first terminal, use kubectl get to view the creation of the StatefulSet's Pods.
$ 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
Check the pod's order index
For a StatefulSet with N replicas, Pods are created in the order of {0…N-1} when they are deployed. In the first terminal we can see the following information:
$ kubectl get pods -w -l role=stateful
NAME READY STATUS RESTARTS AGE
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 19s
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 18s
Note that the web-1 Pod will not be started until the web-0 Pod is in the Running and Ready states.
As mentioned in the StatefulSets concept, Pods in a StatefulSet have a stable and unique identity. This flag is based on the unique sequential index assigned to each Pod by the StatefulSet controller. Pod names are of the form <statefulset name>-<ordinal index>
. The web StatefulSet has two replicas, so it creates two Pods: web-0 and web-1.
The command above creates two Pods, each running an NGINX web server. Get the nginx Service and web StatefulSet to verify that they were created successfully.
$ kubectl get service nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx None <none> 80/TCP 12s
$ kubectl get statefulset web
NAME DESIRED CURRENT AGE
web 2 1 20s
Use a stable network identity
Each Pod has a stable hostname based on its sequential index. Execute hostname in each Pod with kubectl exec.
$ for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
We then use kubectl run to run a container that provides the nslookup command. By doing an nslookup on the Pods' hostnames, you can check their DNS addresses inside the cluster.
$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
nslookup web-0.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.6
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.6
The CNAME of the headless service points to the SRV record (logging each Pod in the Running and Ready state). The SRV record points to a record entry that contains the Pod's IP address.
Then let's look at deleting the Pod under the StatefulSet:
View StatefulSet Pods in a terminal:
$ kubectl get pod -w -l role=stateful
Use kubectl delete in another terminal to delete all Pods in the StatefulSet.
$ kubectl delete pod -l role=stateful
pod "web-0" deleted
pod "web-1" deleted
Wait for the StatefulSet to restart them and both Pods become Running and Ready.
$ kubectl get pod -w -l app=nginx
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 34s
Then use kubectl exec and kubectl run again to view the hostname of the Pod and the DNS entries inside the cluster.
$ for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
nslookup web-0.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.7
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.8
We can see that the pod's ordinal number, hostname, SRV entry, and record name have not changed, but the IP address associated with the pod may have changed. So this is why it is important not to use the IP address of the Pod in the StatefulSet to connect from other applications. In general, we can directly connect through SRV records: web-0.nginx, web-1.nginx, because they are stable, and when your Pod status changes to Running and Ready, your application can discover them the address of.
Similarly, we can check the final binding status of PV and PVC:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 1Gi RWO Recycle Bound default/www-web-0 1h
pv002 1Gi RWO Recycle Bound default/www-web-1 1h
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pv001 1Gi RWO 22m
www-web-1 Bound pv002 1Gi RWO 22m
The use of storage volumes will be explained later, so we will not explain it here for the time being to avoid confusion.
Of course, StatefulSet also has other features. In actual projects, we still rarely go back to deploy our stateful services directly through StatefulSet, unless you can fully hold it yourself. For some specific services, we may use more Advanced Operator to deploy, such as etcd-operator, prometheus-operator, etc. These applications can manage stateful services well, instead of simply using a StatefulSet to deploy a Pod, because for stateful applications The most important thing is data recovery, failover and so on.