Saltar al contenido principal

DaemonSets y StatefulSets en Kubernetes

Ya hemos visto los deployments, pero existen otros objetos similares que nos permiten gestionar múltiples pods de forma automática. En este capítulo vamos a verlos: los DaemonSets y los StatefulSets.

🎥 Vídeo completo, utilicemos los capítulos de youtube para saltar a la sección que nos interese: https://youtu.be/zNEKiAy1F6Q

DaemonSets y StatefulSets

Al igual que los deployments, permiten gestionar pods de forma automática, pero tienen unas características diferentes que los hacen más adecuados para ciertos casos de uso.

Comparemos primero los Deployments con los DaemonSets y StatefulSets:

CaracterísticaDeploymentsDaemonSetsStatefulSets
Propósito principalGestionar aplicaciones sin estadoEjecutar pods en todos los nodosGestionar aplicaciones con estado
EscalabilidadEscalado automático y manualNo escalable, un pod por nodoEscalado manual
Identidad de los podsNo garantiza identidad únicaNo garantiza identidad únicaGarantiza identidad única
Persistencia de datosNo garantiza persistenciaNo garantiza persistenciaVolumen por réplica (volumeClaimTemplates)
Casos de uso comunesAplicaciones web, APIsAgentes de monitoreo, loggingBases de datos, sistemas distribuidos
Distribución de podsBasado en el número deseadoUno por nodo o subconjunto de nodosBasado en el número deseado
Orden de despliegueNo garantiza orden específicoNo garantiza orden específicoGarantiza orden de despliegue

DaemonSets​

Los DaemonSets son objetos de Kubernetes que garantizan que un pod se ejecute en todos los nodos de un clúster, o en un subconjunto específico de ellos. Esto es útil para aplicaciones que tienen que ejecutarse en cada nodo, como agentes de monitorización, recolectores de logs o servicios de red.

Si un nodo se añade al clúster, el DaemonSet automáticamente crea un pod en ese nodo. Si un nodo se elimina, el pod asociado también se elimina. Simple y efectivo.

Veamos un ejemplo de un DaemonSet que ejecuta un pod en todos los nodos del clúster:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
labels:
k8s-app: fluent-bit-logging
spec:
selector:
matchLabels:
name: fluent-bit
template:
metadata:
labels:
name: fluent-bit
spec:
containers:
- name: fluent-bit
image: fluent/fluent-bit:5.1.3
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi

Este DaemonSet ejecutará un pod de Fluent Bit en cada nodo del clúster. Fluent Bit es un recolector de logs ligero que puede recopilar y enviar logs a diferentes destinos; en este caso podemos suponer que se está utilizando para recopilar los logs de todos los nodos del clúster (en un despliegue real montaríamos además /var/log del nodo con un volumen hostPath y le pasaríamos su configuración).

Para aplicar la configuración anterior, usaríamos el siguiente comando:

kubectl apply -f daemonset.yaml

Podríamos consultar el estado del DaemonSet con el comando:

kubectl get daemonset fluent-bit

Como vemos, todos estos objetos se gestionan de forma similar a los deployments: solo hay que especificar el tipo de objeto después de las instrucciones get, edit, describe o delete.

Podríamos borrar el DaemonSet con el siguiente comando:

kubectl delete daemonset fluent-bit

StatefulSets​

Los StatefulSets son objetos de Kubernetes que se utilizan para gestionar aplicaciones con estado. A diferencia de los deployments, los StatefulSets garantizan que los pods tengan una identidad única y estable, lo que es esencial para aplicaciones como bases de datos o sistemas distribuidos.

Cada pod recibe un nombre único y predecible (redis-0, redis-1, redis-2...) y un nombre DNS estable que no cambia, aunque el pod se reinicie o se reprograme en otro nodo. Además, si lo declaramos con volumeClaimTemplates, cada pod va asociado a su propio volumen persistente, que se mantiene incluso si el pod se elimina.

¿Ya nos imaginamos por dónde van los tiros? Efectivamente, esto es ideal para bases de datos o sistemas con almacenamiento persistente.

Veamos un ejemplo de un StatefulSet que ejecuta Redis con un maestro y dos réplicas. El maestro acepta escrituras y las réplicas copian sus datos en tiempo real (y solo admiten lecturas):

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:8.0
command: ["sh", "-c"]
args:
- |
if [ "$(hostname)" = "redis-0" ]; then
exec redis-server
else
exec redis-server --replicaof redis-0.redis 6379
fi
ports:
- containerPort: 6379
name: redis

El truco está en el script de arranque: como el nombre de cada pod es predecible, el que se llama redis-0 arranca como maestro y el resto se conectan a él como réplicas a través de su DNS estable, redis-0.redis. Esto solo es posible gracias a la identidad fija que dan los StatefulSets; con un Deployment los nombres serían aleatorios.

Ojo, es un ejemplo didáctico: si el maestro cae, ninguna réplica se promociona automáticamente. En producción se usa Redis Sentinel o un operador que gestione esa conmutación por error (failover).

Fijémonos en el campo serviceName: los StatefulSets necesitan un servicio "headless" asociado (por eso lo declaramos arriba con clusterIP: None), que es el que proporciona a cada pod su nombre DNS estable. Veremos los servicios en detalle en el capítulo de Services.

Para no complicar el ejemplo hemos dejado fuera el almacenamiento, así que los datos se pierden si un pod se recrea. En un caso real añadiríamos volumeClaimTemplates para que cada réplica tenga su propio volumen persistente; lo veremos en Almacenamiento y volúmenes en Kubernetes.

Para aplicar la configuración anterior, usaríamos el siguiente comando:

kubectl apply -f statefulset.yaml

Para comprobar que la replicación funciona, escribimos una clave en el maestro y la leemos desde una réplica:

kubectl exec redis-0 -- redis-cli set saludo hola
kubectl exec redis-1 -- redis-cli get saludo
kubectl exec redis-1 -- redis-cli info replication # role:slave, master_host:redis-0.redis

Y de igual forma que con los anteriores, podríamos utilizar los comandos get, edit, describe o delete para gestionar el StatefulSet:

kubectl <comando> statefulset redis

Conclusión​

Junto con los deployments, ya hemos visto los principales tipos de objetos que nos permiten gestionar pods de forma automática en Kubernetes. En el siguiente capítulo veremos los jobs y cronjobs, que son objetos que nos permiten ejecutar tareas programadas o de forma puntual.

No nos preocupemos, porque iremos viendo todos estos objetos en profundidad en los casos prácticos.


Volver al índice