Skip to content

Replicación

Un cluster kubernetes se compone de varias máquinas virtuales o máquinas físicas independientes.

Para aprender, o hacer pruebas, puedes simular un cluster multi-node con minikube.

Asegúrate de cambiar la configuración de cpus y memory en función del número de nodos simulados que utilices!

Terminal window
$ minikube start --nodes 4 -p multi
...

Obtén la lista de los nodos:

Terminal window
$ 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

También puedes comprobar el estado de tus nodos:

Terminal window
$ minikube status -p multi
multi
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
multi-m02
type: Worker
host: Running
kubelet: Running
...

Un ReplicationSet és un recurso que garantiza que un grupo de Pods siempre están ejecutándose.

Un Pod puede desaparecer por cualquier razón, por ejemplo que el nodo dónde se ejecuta el Pod desaparece del cluster o que el Pod ha sido desalojado del nodo.

Un ReplicaSet monitoriza constantemente mediante un “label selector” una lista de Pods que se están ejecutando, y se asegura que el número de Pods en ejecución sea igual al número deseado mediante la creación o eliminación de Pods a partir de una plantilla de Pod.

flowchart TB
  start@{shape: circle, label: "Comenzar" }
  start --> find
  style start fill:#00f

  watch(["Esperar notificación de modificación de recursos"])
  style watch fill:#048
  watch == notificación recibida ==> find


  find([Encontrar Pods que hacen match en un 'label selector'])
  find ==> compare
  style find fill:#080
  
  compare@{ shape: hex, label: "Comparar número de Pods encontrados con el número de pots deseados" }
  compare == faltan ==> few

  compare -- ok --> watch

  few([Crear Pods adicionales a partir de la plantilla])
 
  many([Eliminar los Pods que sobran])
  few --> watch
  compare == sobran ==> many
  many --> watch
  style few fill:#800
  style many fill:#800

Por tanto, un ReplicaSet necesita tres elementos fundamentales:

  • Un label selector, que determina que Pods tiene que controlar
  • Un replica count que especifica el número deseado de Pods que deberían estar en ejecución
  • Un Pod template que se utiliza cuando se crean nuevas réplicas del Pod.

En cualquier momento puedes modificar el número de replicas, pero los cambios en el “label selector” y el “Pod template” no afectan a los Pods que se están ejecutando.

A continuación crea un fichero 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:

Terminal window
$ kubectl apply -f nginx.yaml
replicaset.apps/nginx created

Puedes ver que se han creado tres Pods con la etiqueta nginx en tres nodos diferentes:

Terminal window
$ 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 los Pods en nodos diferentes para “no tener todos los huevos en la misma cesta”.

Borra uno de los Pods:

Terminal window
$ kubectl delete pod nginx-78wzt
pod "nginx-78wzt" deleted

Y verifica que el controlador de replicación crea un nuevo Pod:

Terminal window
$ 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

Como hemos dicho al principio, un ReplicationSet és un recurso igual que un Pod.

Por tanto, puedes obtener una lista de todos los ReplicaSet que se han creado:

Terminal window
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 96s

Así com una descripción de un controlador de replicación determinado:

Terminal window
$ 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 lista de eventos muestra las acciones realizadas hasta el momento por el controlador: ha creado 4 Pods.

Cuando pides a kubernetes que despliegue un {% link ”./pod” %}, el despliegue se hará en cualquier nodo que esté disponible.

El problema es que si este nodo “muere” …

Terminal window
$ minikube -p multi node stop multi-m02
Stopping node "multi-m02" ...
🛑 Apagando "multi-m02" mediante SSH...
🛑 Successfully stopped node multi-m02

El nodo ya no está Ready:

Terminal window
$ 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

Importante. El resultado no es inmediato porque el cluster primero se tiene que asegurar que no es un problema temporal de conexión de pocos segundos.

Si miras las lista de Pods, puedes ver el Pod nginx-lvw9l está Running en el nodo multi-m02

Terminal window
$ 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>

Aunque puedes verificar que el Pod ya no está ejecutándose:

Terminal window
$ 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 motivo es que Kubernetes espera un rato para asegurarse de que definitivamente la falta de conexión con el nodo no es por un fallo temporal en la red o porque Kubelet se está reiniciando.

Pero después de ese tiempo, Kubernetes notifica un cambio de recursos y el controlado de recursos nginx crea un nuevo Pod:

Terminal window
$ 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>

Vuelve a arrancar el nodo multi-m02:

Terminal window
$ 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!

Un controlador sólo gestiona los Pods que coinciden con su selector de etiquetas.

Para saber a que controlador está asociado un Pod en ese momento, puedes mirar el atributo metadata.ownerReferences:

Terminal window
$ 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 le importa si añades etiquetas adicionales a los Pods que gestiona:

Terminal window
$ kubectl label pod nginx-zbw6q env=prod
pod/nginx-zbw6q labeled

Puedes ver que los Pods son los mismos que antes porque este cambio no afecta de ningun manera al ReplicaSet:

Terminal window
$ 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

Pero si cambias el valor de la etiqueta app como se muestra a continuación:

Terminal window
$ kubectl label pod nginx-lvw9l app=nginx-old --overwrite
pod/nginx-lvw9l labeled

El ReplicaSet sólo encontrará dos Pods etiquetados como app=nginx, y creará un nuevo Pod con esta etiqueta:

Terminal window
$ 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 --overwrite es necesario porque de esta forma no modificarás de manera accidental una etiqueta.

Puedes verificar que el Pod nginx-lvw9l ya no está gestionado por el controlador:

Terminal window
$ kubectl get pods nginx-lvw9l -o=jsonpath='{.metadata.ownerReferences[0]}'

Esto es útil cuando un Pod no funciona correctamente y quieres probar que está pasando: lo sacas del alcance del controlador, que creará automáticamente un Pod para reemplazarlo, y puedes depurar o averiguar que está sucediendo para luego eliminarlo.

Puedes modificar el número de Pods cambiando el valor del atributo spec.replicas.

Puedes aumentar el número de Pods

Terminal window
$ 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 reducir el número de Pods:

Terminal window
$ 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

Cuando eliminar un ReplicaSet mediante kubectl delete, también se eliminan los Pods a menos que utilices el flag --cascade=orphan:

Terminal window
$ 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 vuelves a crea de nuevo el ReplicaSet, sólo se necesita crear un nuevo Pod para satisfacer las restricciones:

Terminal window
$ 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

Borra todos los recursos:

{% sol %}

Terminal window
$ 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.

{% endsol %}

En un ReplicaSet, Kubernetes despliega el número de Pods indicados en el recurso en los nodos del cluster que le parezcan mejor.

En cambio, en un DaemonSet Kubernetes despiega un único Pod para cada nodo de cluster.

Esto es útil para Pods de sistema com puede ser un recopilador de “logs”, un monitor de recursos, el proceso kube-proxy, etc.

Por ejemplo, Fluentd es un recopilador de datos para unificar el registro de eventos del sistema.

Crea el fichero 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

Puedes ver que en la configuración del recurso utilizamos un selector de etiquetas para limitar los nodos en que se desplegará el Pod.

Por ejemplo, etiqueta el nodo multi-m02 con fluentd-enabled=true:

Terminal window
$ kubectl label node multi-m02 fluentd-enabled=true
node/multi-m02 labeled

Crea el recurso fluentd:

Terminal window
$ kubectl apply -f fluentd.yaml
daemonset.apps/fluentd created

Puedes ver que sólo se ha desplegado un Pod fluend-????? en el cluster:

Terminal window
$ 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 fichero fluentd.yaml y elimina el selector:

...
spec:
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:latest

Actutaliza el recurso:

Terminal window
$ kubectl apply -f fluentd.yaml
daemonset.apps/fluentd configured

Ahora se crea un Pod fluend-????? en cada nodo del cluster:

Terminal window
$ 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>

Vuelve a añadir el selector de nodo y verifica que se eliminan todos los Pods excepto el de multi-m02:`

Terminal window
$ 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 la etiqueta del nodo multi-m02 a fluentd-enabled=false y verifica que el Pod fluentd-xqlvp se elimina:

Terminal window
$ 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>

El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.

©2022-2025 xtec.dev