1. Introducción
La relación desigual entre las instancias y las aplicaciones en las que las instancias tienen dependencias de datos externos se denominan "aplicaciones con estado".
La denominada relación desigual entre instancias significa que para las aplicaciones distribuidas, a menudo hay dependencias relativamente grandes entre cada instancia y cada aplicación. Por ejemplo, una aplicación debe iniciarse antes que otras aplicaciones, de lo contrario no se iniciarán otras aplicaciones.
La aplicación más importante que tiene una dependencia de datos externos es la aplicación de base de datos. Para las aplicaciones de base de datos, necesitamos almacenar sus datos de manera persistente. Si es una aplicación sin estado, reiniciar los datos en la base de datos y la aplicación perderá contacto, que es obviamente una violación Nuestra intención original no era ponerlo en producción.
Por lo tanto, para resolver el soporte efectivo de aplicaciones con estado en Kubernetes, Kubernetes usa StatefulSet para organizar y administrar aplicaciones con estado.
StatefulSet es similar a ReplicaSet. La diferencia es que puede controlar la secuencia de inicio de los pods y establece un identificador único para cada pod. Tiene las siguientes funciones:
-
Identificador de red único y estable
-
Almacenamiento estable y persistente
-
Despliegue y escalado ordenados y elegantes
- Actualización continua ordenada y automática
El diseño de StatefulSet es fácil de entender y abstrae el mundo real en las dos situaciones siguientes:
(1) Estado topológico. Esto significa que existe una relación asimétrica entre las aplicaciones. Las aplicaciones deben iniciarse en un orden determinado. Incluso si la aplicación se reinicia, debe reiniciarse en el orden especificado y su identificación de red debe ser la misma que la original después del reinicio. para que se pueda garantizar el acceso original El usuario puede acceder al nuevo Pod a través del mismo método;
(2), estado de almacenamiento. Esto significa que la aplicación está vinculada a los datos almacenados, sin importar cuándo, sin importar la situación, para la aplicación, siempre que los datos en el almacenamiento no cambien, los datos leídos deben ser los mismos;
Entonces, la función principal de StatefulSet es registrar el estado del Pod de cierta manera y luego restaurar su estado de alguna manera cuando se vuelve a crear el Pod.
二 、 Servicio sin cabeza
Antes de presentar StatefulSet, primero comprendamos qué es Headless Service.
Sabemos que en Kubernetes, el servicio es una forma de proporcionar acceso externo a un grupo de pods. Por lo general, usamos el Servicio para acceder al Pod de las siguientes dos formas:
(1) A través de la IP del clúster, esta IP del clúster es equivalente a VIP. Cuando visitamos esta IP, la solicitud se reenviará al Pod de fondo;
(2) A través de DNS , de esta manera, primero debe asegurarse de que haya un servicio DNS en el clúster de Kubernetes. En este momento, siempre que accedamos a "my-service.my-namespace.svc, cluster.local", podemos acceder al Pod de backend enviado por proxy por el Servicio llamado my-service;
Para el segundo método, existen los siguientes dos métodos de procesamiento:
(1) Servicio normal, es decir, resolver el nombre de dominio y obtener la IP del clúster, y luego acceder de acuerdo con el método uno;
(2), Servicio sin cabeza, es decir , resuelve el nombre de dominio para obtener la dirección IP de un Pod en el backend, de modo que se pueda acceder a él directamente;
Para el segundo método de procesamiento, podemos ver que no hay necesidad de IP de clúster, pero la dirección IP del Pod de backend se resuelve directamente a través del nombre de dominio para el acceso.
La siguiente es una definición de archivo YAML simple de Headless Service:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
Se puede ver en el archivo YAML anterior que no hay mucha diferencia con nuestra definición de servicio normal. La única diferencia es que la IP del clúster está configurada en Ninguno, es decir, no se necesita ningún clúster. Creamos este Servicio a través de kubectl apply -f y luego verifique que la IP del clúster del servicio sea Ninguna.
El Servicio creado de esta manera es un Servicio sin cabeza, no tiene un VIP, por lo que expondrá el Pod que envió como proxy en forma de registros DNS.
Tres, use StatefulSet
Cree el PV antes de crear StatefulSet, de la siguiente manera:
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
Luego ejecute kubectl apply -f para iniciar PV, de la siguiente manera:
[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
Puede ver que los estados de los dos PV están disponibles y luego escribir el archivo YAML del 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
Tenga en cuenta que el archivo YAML anterior asociado con volumeMounts es un nuevo atributo: volumeClaimTemplates, este atributo declarará automáticamente un objeto pvc y un pv para la administración, y serviceName: "nginx" significa que el headless de nginx se usa cuando se ejecuta el bucle de control. Servicio para guardar la identidad resoluble del Pod.
Entonces aquí abrimos dos ventanas de terminal. En la primera terminal, use kubectl get para ver la creación de los Pods del StatefulSet.
$ kubectl get pods -w -l role=stateful
En otra terminal, use kubectl create para crear el Headless Service y StatefulSet definidos en statefulset-demo.yaml.
$ kubectl create -f statefulset-demo.yaml
service "nginx" created
statefulset.apps "web" created
Luego observamos la secuencia de inicio del 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
A través del proceso de creación anterior, podemos ver que StatefulSet numera los Pods que administra. Su regla de nomenclatura es [statefulset-name] - [index], y su índice comienza en 0, que es el mismo que cada instancia de Pod de StatefulSet. Uno correspondencia, nunca repetir. Más importante aún, el proceso de creación de pod es secuencial. Como se indicó anteriormente, web-1 entra en estado pendiente después de que web-0 entra en estado de ejecución.
Usamos el comando para ver los resultados de su creación:
[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
Cuando ambos pods ingresan al estado de ejecución, puede ver sus respectivas identidades de red. Podemos verlos a través de kubectl exec, de la siguiente manera:
[root@master statefulset]# kubectl exec web-0 -- sh -c 'hostname'
web-0
[root@master statefulset]# kubectl exec web-1 -- sh -c 'hostname'
web-1
Puede ver que el nombre de host y el nombre de pod de los dos pods son iguales, y a todos se les asignan los números correspondientes. A continuación, usamos DNS para acceder al Servicio Headless.
Primero iniciamos un Pod con el siguiente comando:
kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
Luego, use nslookup para analizar el servicio sin cabeza correspondiente a un pod en este 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
A partir del análisis de los resultados de nslookup, al acceder a web-0.nginx, se analiza la IP del Pod web-0, y la otra es la misma.
En este momento, si eliminamos los dos Pods, observe el proceso de reinicio del Pod:
[root@master statefulset]# kubectl delete pod -l role=stateful
pod "web-0" deleted
pod "web-1" deleted
Luego verifique la secuencia de reinicio de la siguiente manera:
[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
Podemos ver que después de eliminar el Pod, su secuencia de reinicio aún se reinicia de acuerdo con el número original y su identificación de red sigue siendo la misma que antes.
A través de esta estricta regla de correspondencia, StatefulSet garantiza la estabilidad de la identidad de red del Pod. A través de este método, el estado topológico del Pod se puede arreglar de acuerdo con el nombre + número del Pod. Además, Kubernetes también proporciona una entrada de acceso fija y única para cada Pod, es decir, el registro DNS del Pod.
También podemos comprobar la unión de PV y 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
Por lo tanto, clasificamos StatefulSet de la siguiente manera:
(1), StatefulSet administra directamente Pod. Esto se debe a que las instancias de pod en StatefulSet no son exactamente las mismas que las instancias de pod en ReplicaSet. Son ligeramente diferentes. Por ejemplo, el nombre y el nombre de host de cada pod son diferentes, y la forma en que StatefulSet distingue estas instancias es para agregar el Número de Pod;
(2), Kubernetes genera un registro con el mismo número en el servidor DNS para este Pod numerado a través del Servicio Headless. Siempre que StatefulSet pueda garantizar que el número de este Pod se mantenga sin cambios, el registro DNS similar a web-0.nginx.default.svc.cluster.local en el Servicio no cambiará, y la dirección IP del Pod resuelta por este registro Se actualiza automáticamente con la recreación del Pod;
(3) StatefulSet también puede asignar y crear un PVC con el mismo número que el Pod para cada Pod. De esta manera, Kubernetes puede vincular el PV correspondiente a este PVC a través del mecanismo de volumen persistente, para garantizar que cada pod tenga un volumen independiente. En este caso, incluso si se elimina el Pod, su PVC y PV correspondientes se conservarán, por lo que cuando se vuelva a crear el Pod, Kubernetes encontrará el PVC con el mismo número y montará el volumen correspondiente al PVC. los datos anteriores del Volumen anterior;
Cuatro, resumen
Una de las funciones principales del controlador StatefulSet es numerarlos al crear pods con la plantilla de pod y completar las tareas en el orden de los números. Cuando el bucle de control del StatefulSet descubre que el estado real del pod no es coherente con el estado esperado, también operará el Pod en orden.
Por supuesto, StatefulSet también tiene otras características. En proyectos reales, rara vez volvemos e implementamos nuestros servicios con estado directamente a través de StatefulSet, a menos que usted pueda mantenerlo por completo. Para algunos servicios específicos, podemos usar más Operadores avanzados implementados, como como etcd-operator, prometheus-operator, etc. Estas aplicaciones pueden administrar muy bien los servicios con estado, en lugar de usar un StatefulSet para implementar un Pod, porque para las aplicaciones con estado, lo más importante es la recuperación de datos, la conmutación por error, etc.
Finalizar