La forma de garantir la disponibilitat és mantenir un conjunt estable de rèpliques de Pods executant-se en tot moment
Introducció
Un clúster kubernetes es compon de diverses màquines virtuals o màquines físiques independents.
Entorn de treball
Assegura’t de canviar la configuració de cpus
i memory
en funció del nombre de nodes simulats que utilitzis!
$ minikube start --nodes 4 -p multi
...
Obtén la llista dels nodes:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
multi Ready control-plane 5m27s v1.32.0
multi-m02 Ready <none> 4m58s v1.32.0
multi-m03 Ready <none> 4m29s v1.32.0
multi-m04 Ready <none> 4m v1.32.0
També pots comprovar l’estat dels teus nodes:
$ minikube status -p multi
multi
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
multi-m02
type: Worker
host: Running
kubelet: Running
...
ReplicaSet
Un ReplicationSet
és un recurs que garanteix que un grup de Pods sempre s’estan executant.
Un Pod pot desaparèixer per qualsevol raó, per exemple que el node on s’executa el Pod desapareix del clúster o que el Pod ha estat desallotjat del node.
Un ReplicaSet
monitoritza constantment mitjançant un “label selector” una llista de Pods que s’estan executant, i s’assegura que el nombre de Pods en execució sigui igual al nombre desitjat mitjançant la creació o eliminació de Pods a partir d’una plantilla de Pod.
Per tant, un ReplicaSet
necessita tres elements fonamentals:
-
Un label selector, que determina quins Pods ha de controlar
-
Un replica count que especifica el nombre desitjat de Pods que haurien d’estar en execució
-
Un Pod template que s’utilitza quan es creen noves rèpliques del Pod.
En qualsevol moment pots modificar el nombre de rèpliques, però els canvis en el “label selector” i el “Pod template” no afecten els Pods que s’estan executant.
A continuació crea un fitxer nginx.yaml
:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Crea el ReplicaSet
:
$ kubectl apply -f nginx.yaml
replicaset.apps/nginx created
Pots veure que s’han creat tres Pods amb l’etiqueta nginx
en tres nodes diferents:
$ kubectl get pods -o wide -L app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES APP
nginx-78wzt 1/1 Running 0 11s 10.244.2.3 multi-m03 <none> <none> nginx
nginx-mxf4c 1/1 Running 0 11s 10.244.1.4 multi-m02 <none> <none> nginx
nginx-wdjsh 1/1 Running 0 11s 10.244.3.4 multi-m04 <none> <none> nginx
Kubernetes intenta desplegar els Pods en nodes diferents per “no tenir tots els ous al mateix cistell”.
Esborra un dels Pods:
$ kubectl delete pod nginx-78wzt
pod "nginx-78wzt" deleted
I verifica que el controlador de replicació crea un nou Pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-lvw9l 1/1 Running 0 19s
nginx-mxf4c 1/1 Running 0 54s
nginx-wdjsh 1/1 Running 0 54s
Com hem dit al principi, un ReplicationSet
és un recurs igual que un Pod
.
Per tant, pots obtenir una llista de tots els ReplicaSet
que s’han creat:
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 96s
Així com una descripció d’un controlador de replicació determinat:
$ kubectl describe rs nginx
Name: nginx
Namespace: default
Selector: app=nginx
Labels: <none>
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers: ...
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m9s replicaset-controller Created pod: nginx-wdjsh
Normal SuccessfulCreate 2m9s replicaset-controller Created pod: nginx-mxf4c
Normal SuccessfulCreate 2m9s replicaset-controller Created pod: nginx-78wzt
Normal SuccessfulCreate 94s replicaset-controller Created pod: nginx-lvw9l
La llista d’esdeveniments mostra les accions realitzades fins al moment pel controlador: ha creat 4 Pods.
Responent a una fallada de node
Quan demanes a kubernetes que desplegui un Pod, el desplegament es farà en qualsevol node que estigui disponible.
El problema és que si aquest node “mor” …
$ minikube -p multi node stop multi-m02
✋ Stopping node "multi-m02" ...
🛑 Apagando "multi-m02" mediante SSH...
🛑 Successfully stopped node multi-m02
El node ja no està Ready
:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
multi Ready control-plane 3d v1.32.0
multi-m02 NotReady <none> 3d v1.32.0
multi-m03 Ready <none> 3d v1.32.0
multi-m04 Ready <none> 3d v1.32.0
Important. El resultat no és immediat perquè el clúster primer s’ha d’assegurar que no és un problema temporal de connexió de pocs segons.
Si mires la llista de Pods, pots veure que el Pod nginx-lvw9l
està Running
al node multi-m02
…
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-lvw9l 1/1 Running 0 3m42s 10.244.2.4 multi-m03 <none> <none>
nginx-mxf4c 1/1 Running 0 4m17s 10.244.1.4 multi-m02 <none> <none>
nginx-wdjsh 1/1 Running 0 4m17s 10.244.3.4 multi-m04 <none> <none>
Tot i que pots verificar que el Pod ja no s’està executant:
$ kubectl exec nginx-lvw9l -- bash
error: Internal error occurred: error sending request: Post "https://192.168.49.3:10250/exec/default/nginx-gmkgq/nginx?command=bash&error=1&output=1": dial tcp 192.168.49.3:10250: connect: no route to host
El motiu és que Kubernetes espera una estona per assegurar-se que definitivament la falta de connexió amb el node no és per una fallada temporal a la xarxa o perquè Kubelet s’està reiniciant.
Però després d’aquest temps, Kubernetes notifica un canvi de recursos i el controlador de recursos nginx
crea un nou Pod:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-lvw9l 1/1 Running 0 9m36s 10.244.2.4 multi-m03 <none> <none>
nginx-mxf4c 1/1 Terminating 0 10m 10.244.1.4 multi-m02 <none> <none>
nginx-wdjsh 1/1 Running 0 10m 10.244.3.4 multi-m04 <none> <none>
nginx-zbw6q 1/1 Running 0 50s 10.244.0.4 multi <none> <none>
Torna a arrencar el node multi-m02
:
$ minikube -p multi node start multi-m02
👍 Starting "multi-m02" worker node in "multi" cluster
🚜 Pulling base image v0.0.46 ...
🔄 Restarting existing docker container for "multi-m02" ...
🐳 Preparando Kubernetes v1.32.0 en Docker 27.4.1...
🔎 Verifying Kubernetes components...
🌟 Complementos habilitados:
😄 Successfully started node multi-m02!
Etiquetes
Un controlador només gestiona els Pods que coincideixen amb el seu selector d’etiquetes.
Per saber a quin controlador està associat un Pod en aquest moment, pots mirar l’atribut metadata.ownerReferences
:
$ kubectl get pods nginx-lvw9l -o=jsonpath='{.metadata.ownerReferences[0]}'
{
"apiVersion":"apps/v1",
"blockOwnerDeletion":true,
"controller":true,
"kind":"ReplicaSet",
"name":"nginx",
"uid":"bb526ba4-f15a-4517-a056-b6ef8c8cd531"
}
A un ReplicaSet
no li importa si afegeixes etiquetes addicionals als Pods que gestiona:
$ kubectl label pod nginx-zbw6q env=prod
pod/nginx-zbw6q labeled
Pots veure que els Pods són els mateixos que abans perquè aquest canvi no afecta de cap manera al ReplicaSet
:
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-lvw9l 1/1 Running 0 14m app=nginx
nginx-wdjsh 1/1 Running 0 15m app=nginx
nginx-zbw6q 1/1 Running 0 5m55s app=nginx,env=prod
Però si canvies el valor de l’etiqueta app
com es mostra a continuació:
$ kubectl label pod nginx-lvw9l app=nginx-old --overwrite
pod/nginx-lvw9l labeled
El ReplicaSet
només trobarà dos Pods etiquetats com app=nginx
, i crearà un nou Pod amb aquesta etiqueta:
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-gvt68 1/1 Running 0 83s nginx
nginx-lvw9l 1/1 Running 0 28m nginx-old
nginx-wdjsh 1/1 Running 0 29m nginx
nginx-zbw6q 1/1 Running 0 19m nginx
El flag és necessari perquè d’aquesta manera no modificaràs de manera accidental una etiqueta. --overwrite
Pots verificar que el Pod nginx-lvw9l
ja no és gestionat pel controlador:
$ kubectl get pods nginx-lvw9l -o=jsonpath='{.metadata.ownerReferences[0]}'
Això és útil quan un Pod no funciona correctament i vols provar què està passant: el treus de l’abast del controlador, que crearà automàticament un Pod per reemplaçar-lo, i pots depurar o esbrinar què està succeint per després eliminar-lo.
Escalant horitzontalment
Pots modificar el nombre de Pods canviant el valor de l’atribut spec.replicas
.
Pots augmentar el nombre de Pods:
$ kubectl scale rs nginx --replicas=5
replicaset.apps/nginx scaled
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-gvt68 1/1 Running 0 21m nginx
nginx-lvw9l 1/1 Running 0 48m nginx-old
nginx-m7b46 1/1 Running 0 39s nginx
nginx-sm7zx 1/1 Running 0 39s nginx
nginx-wdjsh 1/1 Running 0 49m nginx
nginx-zbw6q 1/1 Running 0 40m nginx
O reduir el nombre de Pods:
$ kubectl scale rs nginx --replicas=2
replicaset.apps/nginx scaled
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-lvw9l 1/1 Running 0 51m nginx-old
nginx-wdjsh 1/1 Running 0 52m nginx
nginx-zbw6q 1/1 Running 0 43m nginx
Eliminar un ReplicaSet
Quan elimines un ReplicaSet
mitjançant kubectl delete
, també s’eliminen els Pods a menys que utilitzis el flag --cascade=orphan
:
$ kubectl delete rs nginx --cascade=false
replicaset.apps "nginx" deleted
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-lvw9l 1/1 Running 0 55m nginx-old
nginx-wdjsh 1/1 Running 0 56m nginx
nginx-zbw6q 1/1 Running 0 47m nginx
Si tornes a crear de nou el ReplicaSet
, només cal crear un nou Pod per satisfer les restriccions:
$ kubectl apply -f nginx.yaml
replicaset.apps/nginx created
$ kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-lnfrd 0/1 ContainerCreating 0 2s nginx
nginx-lvw9l 1/1 Running 0 57m nginx-old
nginx-wdjsh 1/1 Running 0 57m nginx
nginx-zbw6q 1/1 Running 0 48m nginx
Esborra tots els recursos:
$ kubectl delete rs nginx
replicaset.apps "nginx" deleted
$ kubectl delete pod nginx-lvw9l
pod "nginx-lvw9l" deleted
$ kubectl get pods
No resources found in default namespace.
DaemonSet
En un ReplicaSet
, Kubernetes desplega el nombre de Pods indicats en el recurs als nodes del clúster que li semblin millor.
En canvi, en un DaemonSet
Kubernetes desplega un únic Pod per a cada node del clúster.
Això és útil per a Pods de sistema com pot ser un recopilador de “logs”, un monitor de recursos, el procés kube-proxy, etc.
Per exemple, Fluentd és un recopilador de dades per unificar el registre d’esdeveniments del sistema.
Crea el fitxer fluentd.yaml
:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
name: fluentd
template:
metadata:
labels:
name: fluentd
spec:
nodeSelector:
fluentd-enabled: "true"
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:latest
Pots veure que en la configuració del recurs utilitzem un selector d’etiquetes per limitar els nodes en què es desplegarà el Pod.
Per exemple, etiqueta el node multi-m02
amb fluentd-enabled=true
:
$ kubectl label node multi-m02 fluentd-enabled=true
node/multi-m02 labeled
Crea el recurs fluentd
:
$ kubectl apply -f fluentd.yaml
daemonset.apps/fluentd created
Pots veure que només s’ha desplegat un Pod fluentd-?????
al clúster:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-wdh2j 1/1 Running 0 34s 10.244.1.4 multi-m02 <none> <none>
Edita el fitxer fluentd.yaml
i elimina el selector:
...
spec:
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:latest
Actualitza el recurs:
$ kubectl apply -f fluentd.yaml
daemonset.apps/fluentd configured
Ara es crea un Pod fluentd-?????
a cada node del clúster:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-gj4hs 1/1 Running 0 15s 10.244.2.3 multi-m03 <none> <none>
fluentd-gxrfv 1/1 Running 0 15s 10.244.3.3 multi-m04 <none> <none>
fluentd-rp7vz 1/1 Running 0 15s 10.244.0.4 multi <none> <none>
fluentd-xqlvp 1/1 Running 0 11s 10.244.1.5 multi-m02 <none> <none>
Torna a afegir el selector de node i verifica que s’eliminen tots els Pods excepte el de multi-m02
:
$ nano fluentd.yaml
$ kubectl apply -f fluentd.yaml
daemonset.apps/fluentd configured
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-gxrfv 0/1 Completed 0 7m9s 10.244.3.3 multi-m04 <none> <none>
fluentd-xqlvp 1/1 Terminating 0 7m5s 10.244.1.5 multi-m02 <none> <none>
Modifica l’etiqueta del node multi-m02
a fluentd-enabled=false
i verifica que el Pod fluentd-xqlvp
s’elimina:
$ kubectl label node multi-m02 fluentd-enabled=false --overwrite
node/multi-m02 labeled
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-mszqj 0/1 Completed 0 44s 10.244.1.6 multi-m02 <none> <none>