Controladores de Pod en Kubernetes

Los controladores de Pod son proporcionados por el componente kube-controller-manager del nodo maestro. Entre los controladores más comunes se encuentran ReplicationController, ReplicaSet, Deployment, DaemonSet, StatefulSet, Job y CronJob. Cada uno gestiona los objetos Pod de manera distinta.

  1. Controlador ReplicaSet

(1) Introducción a ReplicaSet

Conocido como RS, es una implementación de controlador de Pod que garantiza que la cantidad de réplicas de un Pod coincida exactamente con el número esperado en todo momento. El controlador RS busca en el clúster los objetos Pod que coincidan con su selector de etiquetas. Si la cantidad de objetos activos no coincide con la esperada, elimina los sobrantes o crea nuevos a partir de una plantilla para alcanzar el número deseado. Una vez que se cumple la cantidad esperada, entra en el siguiente ciclo de reconciliación.

Las propiedades de RS, como el número de réplicas, el selector de etiquetas y la plantilla de Pod, se pueden modificar en cualquier momento. Sin embargo, modificar solo el número esperado de réplicas afecta directamente a los Pod existentes. Cambiar el selector de etiquetas puede hacer que los Pod existentes ya no coincidan, y el controlador RS simplemente dejará de contarlos. Además, una vez creado, RS no se preocupa por el contenido real del Pod, por lo que los cambios en la plantilla solo afectan a los nuevos Pod creados posteriormente. En comparación con la creación y gestión manual de Pods, RS ofrece las siguientes funcionalidades:

  • Garantizar la cantidad de Pods: RS se asegura de que el número de réplicas de Pod bajo su control coincida con el valor esperado definido en la configuración. Si no es así, añade los que faltan o elimina los sobrantes.
  • Monitoreo de Pods: Si detecta que un Pod bajo su control no está disponible debido a una falla en el nodo de trabajo, solicita al planificador que cree un Pod de reemplazo en otro nodo.
  • Escalado elástico: Ante fluctuaciones en la carga de trabajo, se puede ajustar dinámicamente la cantidad de Pods a través del controlador RS. Incluso se puede usar el controlador HPA (HorizontalPodAutoscaler) para un escalado automático.

(2) Creación de un ReplicaSet

Al igual que los Pods, la creación de un controlador RS se define mediante un archivo de manifiesto en formato YAML o JSON, y luego se utiliza el comando correspondiente para crearlo.

  • replicas: Número esperado de réplicas de Pod.
  • selector: Selector de etiquetas para emparejar los Pods que controla. Soporta matchLabels y matchExpressions.
  • template: Plantilla de Pod utilizada para crear réplicas cuando sea necesario.
  • minReadySeconds: Tiempo mínimo que un Pod recién creado debe estar funcionando sin fallos para ser considerado listo. El valor predeterminado es 0 segundos.

Ejemplo:

~]# cat rs-ejemplo.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-ejemplo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: rs-demo
  template:
    metadata:
      labels:
        app: rs-demo
    spec:
      containers:
      - name: miapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80
~]# kubectl apply -f rs-ejemplo.yaml
~]# kubectl get replicaset -o wide
NAME                  DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                 SELECTOR
rs-ejemplo            2         2         2       5m20s   miapp        ikubernetes/myapp:v1   app=rs-demo

(3) Pods bajo el control de RS

Existen varias situaciones que pueden provocar que la cantidad de Pods difiera del valor esperado, como la eliminación accidental de un Pod, el cambio de etiquetas de un Pod, la modificación del selector de etiquetas del controlador o una falla en un nodo de trabajo. El ciclo de reconciliación de RS monitorea estas anomalías y actúa en consecuencia.

a. Falta de réplicas de Pod
Cualquier pérdida de Pods relacionados se solventa automáticamente mediante el controlador RS.

Por ejemplo, al eliminar manualmente un Pod:

~]# kubectl delete pods rs-ejemplo-c5k89
pod "rs-ejemplo-c5k89" deleted
~]# kubectl get pods -l app=rs-demo -o wide
NAME               READY   STATUS    RESTARTS   AGE     IP           NODE               NOMINATED NODE
rs-ejemplo-679xq   1/1     Running   0          52s     10.244.1.9   node01.ilinux.io   <none>
rs-ejemplo-sxq7x   1/1     Running   0          9m56s   10.244.3.7   node03.ilinux.io   <none>
</none></none>

Por ejemplo, al modificar las etiquetas de un Pod:

~]# kubectl label pods rs-ejemplo-679xq app= --overwrite
pod/rs-ejemplo-679xq labeled
~]# kubectl get pods -l app=rs-demo -o wide
NAME               READY   STATUS    RESTARTS   AGE    IP            NODE               NOMINATED NODE
rs-ejemplo-d9j9z   1/1     Running   0          2m1s   10.244.2.25   node02.ilinux.io   <none>
rs-ejemplo-sxq7x   1/1     Running   0          17m    10.244.3.7    node03.ilinux.io   <none>
</none></none>

b. Exceso de réplicas de Pod
Si la cantidad de Pods seleccionados por el selector supera el valor esperado, los sobrantes se eliminan automáticamente. Esto significa que cualquier Pod creado de forma independiente o por otro controlador, cuyas etiquetas cambien para coincidir con un controlador que ya tiene suficientes réplicas, será eliminado.

~]# kubectl label pods pod-ejemplo app=rs-demo

c. Visualización de eventos relacionados con Pods

~]# kubectl describe replicasets/rs-ejemplo

(4) Actualización del controlador ReplicaSet

Los componentes principales de RS son el selector de etiquetas, la cantidad de réplicas y la plantilla de Pod. Las actualizaciones suelen centrarse en los campos replicas y template. Modificar la plantilla de Pod no afecta a los Pod existentes, pero al eliminar los antiguos, se pueden crear nuevos basados en la nueva plantilla. Cambiar la cantidad de réplicas implica escalar la aplicación.

a. Cambio de plantilla de Pod: Actualización de aplicación
La plantilla de Pod de RS se puede modificar en cualquier momento, pero solo afecta a los nuevos Pods creados posteriormente.

~]# cat rs-ejemplo-v2.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-ejemplo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: rs-demo
  template:
    metadata:
      labels:
        app: rs-demo
    spec:
      containers:
      - name: nginx
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80

~]# kubectl replace -f rs-ejemplo-v2.yaml

Tras esto, se deben eliminar manualmente los Pods existentes para que el controlador cree nuevos basados en la plantilla actualizada. Sin embargo, para un control más avanzado, se recomienda usar el controlador Deployment.

b. Escalado
Modificar la propiedad replicas en la configuración de RS hace que el controlador ajuste la cantidad de Pods en tiempo real. También se puede usar el comando kubectl scale.

Ejemplo: aumentar las réplicas a 5

~]# kubectl scale replicasets rs-ejemplo --replicas=5
replicaset.extensions/rs-ejemplo scaled
~]# kubectl get replicasets rs-ejemplo
NAME         DESIRED   CURRENT   READY   AGE
rs-ejemplo   5         5         5       3h25m

Para reducir:

~]# kubectl scale replicasets rs-ejemplo --replicas=3

c. Eliminación de un ReplicaSet
Al eliminar un objeto RS con kubectl delete, también se eliminan los Pods que controla. Para evitar la eliminación en cascada, usa la opción --cascade=false.

~]# kubectl delete replicasets rs-ejemplo --cascade=false

Aunque RS es potente, en la práctica, Deployment es el controlador más utilizado.

  1. Controlador Deployment

Conocido como deploy, es otra implementación de controlador que se basa en ReplicaSet para proporcionar actualizaciones declarativas de Pods y RS. Ofrece funcionalidades adicionales:

  • Visualización de eventos y estado: Permite ver el progreso y el estado detallado de una actualización.
  • Rollback: Permite revertir a una versión anterior si se detectan problemas.
  • Versionado: Cada operación sobre un Deployment se guarda en el historial para posibles rollbacks.
  • Pausa y reanudación: Permite pausar y reanudar actualizaciones en cualquier momento.
  • Estrategias de actualización: Soporta Recreate (recreación completa) y RollingUpdate (actualización gradual).

(1) Creación de un Deployment

Un Deployment se construye sobre ReplicaSet e incluye campos como replicas, selector, template y minReadySeconds.

Ejemplo:

~]# cat miapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: miapp-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: miapp
  template:
    metadata:
      labels:
        app: miapp
    spec:
      containers:
      - name: miapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: http
~]# kubectl apply -f miapp-deploy.yaml --record
~]# kubectl get deployment

(2) Estrategias de actualización

Deployment soporta dos estrategias: RollingUpdate (predeterminada) y Recreate. Recreate elimina todos los Pods antiguos antes de crear los nuevos, útil cuando las versiones no son compatibles. RollingUpdate reemplaza gradualmente los Pods antiguos por nuevos, garantizando que el servicio no se interrumpa, pero requiere que la aplicación soporte ambas versiones simultáneamente.

En RollingUpdate, los Pods antiguos y nuevos se gestionan en dos ReplicaSets distintos. Se definen dos propiedades:

  • maxSurge: Número máximo de Pods por encima del valor esperado durante la actualización. Puede ser un número entero o un porcentaje.
  • maxUnavailable: Número máximo de Pods no disponibles durante la actualización. Puede ser un número entero o un porcentaje. El valor predeterminado es 1.

Ambos valores no pueden ser 0 al mismo tiempo. La propiedad minReadySeconds controla la velocidad de la actualización, esperando un tiempo antes de iniciar el siguiente reemplazo.

(3) Actualización de un Deployment

Modificar la plantilla de Pod en un Deployment desencadena una actualización. Se recomienda usar kubectl apply, patch o set image.

Ejemplo: configurar el tiempo de espera y actualizar la imagen

~]# kubectl patch deployments miapp-deploy -p '{"spec": {"minReadySeconds": 5}}'
~]# kubectl set image deployments miapp-deploy miapp=ikubernetes/myapp:v2

Ver el progreso:

~]# kubectl rollout status deployment miapp-deploy
~]# kubectl get deployments miapp-deploy --watch

(4) Lanzamiento Canary

Deployment permite pausar una actualización para realizar un lanzamiento Canary. Se configura maxSurge y maxUnavailable, se inicia la actualización y se pausa inmediatamente después de crear los primeros Pods nuevos.

Ejemplo:

~]# kubectl patch deployments miapp-deploy -p '{"spec":{"strategy":{"rollingUpdate": {"maxSurge": 1, "maxUnavailable": 0} }}}'
~]# kubectl set image deployments miapp-deploy miapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment miapp-deploy

Después de verificar, se reanuda la actualización:

~]# kubectl rollout resume deployments miapp-deploy

(5) Rollback de un Deployment

Para revertir una actualización, se usa kubectl rollout undo.

~]# kubectl rollout undo deployments miapp-deploy
~]# kubectl rollout history deployments miapp-deploy
~]# kubectl rollout undo deployments miapp-deploy --to-revision=2

El rollback se registra como una nueva actualización en el historial.

(6) Escalado

Modificar spec.replicas en un Deployment escala la aplicación. Se puede hacer mediante el archivo de configuración, kubectl edit o kubectl scale.

  1. Controlador DaemonSet

DaemonSet ejecuta una réplica de un Pod en todos los nodos del clúster. Los nuevos nodos que se unan al clúster crean automáticamente el Pod correspondiente, y al eliminar un nodo, el Pod se elimina. Se puede restringir a nodos con etiquetas específicas. Es útil para tareas a nivel de sistema, como:

  • Ejecutar demonios de almacenamiento (glusterfs, ceph).
  • Ejecutar agentes de recolección de logs (fluentd, logstash).
  • Ejecutar agentes de monitoreo (Prometheus Node Exporter, collectd).

(1) Creación de un DaemonSet

Incluye selector, template y minReadySeconds, pero no replicas.

Ejemplo:

~]# cat filebeat-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat-ds
  labels:
    app: filebeat
spec:
  selector:
    matchLabels:
      app: filebeat
  template:
    metadata:
      labels:
        app: filebeat
    spec: 
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env:
        - name: REDIS_HOST
          value: db.linux.io:6379
        - name: LOG_LEVEL
          value: info
~]# kubectl apply -f filebeat-ds.yaml
daemonset.apps/filebeat-ds created

(2) Actualización de un DaemonSet

Soporta RollingUpdate (predeterminado) y OnDelete. RollingUpdate actualiza los Pods uno por uno, usando maxUnavailable para controlar la disponibilidad.

  1. Controlador Job

Job gestiona Pods que ejecutan tareas únicas. Una vez que el proceso en el contenedor finaliza correctamente, el Pod pasa al estado Completed. Si falla, se puede configurar para reiniciar o no. Si el nodo falla, el Pod se reprograma.

Existen dos tipos de Job:

  • Serial: Ejecuta tareas de forma secuencial hasta alcanzar el número deseado de finalizaciones.
  • Paralelo: Permite ejecutar múltiples tareas en paralelo.

(1) Creación de un Job

El campo obligatorio es template. Es importante configurar restartPolicy como Never o OnFailure.

Ejemplo:

~]# cat job-ejemplo.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job-ejemplo
spec:
  template:
    spec:
      containers:
      - name: mitrabajo
        image: alpine
        command: ["/bin/sh", "-c", "sleep 120"]
      restartPolicy: Never
~]# kubectl apply -f job-ejemplo.yaml
~]# kubectl get jobs job-ejemplo

(2) Job Paralelo

Se configura con completions (número total de tareas) y parallelism (número de tareas concurrentes).

Ejemplo:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-multi
spec:
  completions: 5
  parallelism: 2
  backoffLimit: 5
  activeDeadlineSeconds: 100
  template:
    spec:
      containers:
      - name: mitrabajo
        image: alpine
        command: ["/bin/sh", "-c", "sleep 120"]
      restartPolicy: OnFailure

(3) Escalado de un Job

Se puede cambiar la concurrencia con kubectl scale.

~]# kubectl scale jobs job-multi --replicas=2

(4) Eliminación de un Job

Los Jobs completados se pueden eliminar manualmente. Para controlar fallos, se usan activeDeadlineSeconds y backoffLimit.

  1. Controlador CronJob

CronJob gestiona la ejecución periódica de Jobs, similar a crontab en Linux.

(1) Creación de un CronJob

Campos principales:

  • jobTemplate: Plantilla del Job a ejecutar.
  • schedule: Horario en formato cron.
  • concurrencyPolicy: Política de concurrencia (Allow, Forbid, Replace).
  • failedJobHistoryLimit y successfulJobHistoryLimit: Límite de historial.
  • startingDeadlineSeconds: Tiempo de espera para iniciar un Job retrasado.

Ejemplo:

~]# cat cronjob-ejemplo.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-ejemplo
  labels:
    app: micronjob
spec:
  schedule: "*/2 * * * *"
  jobTemplate:
    metadata:
      labels:
        app: micronjob-jobs
    spec:
      parallelism: 2
      template:
        spec:
          containers:
          - name: mitrabajo
            image: alpine
            command:
            - /bin/sh
            - -c
            - date; echo Hello from k8s cluster; sleep 10
          restartPolicy: OnFailure
~]# kubectl apply -f cronjob-ejemplo
~]# kubectl get cronjobs cronjob-ejemplo
NAME              SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob-ejemplo   */2 * * * *   False     0        <none>          22s
</none>

(2) Mecanismo de control de CronJob

CronJob gestiona Jobs. Si un Job anterior no ha finalizado cuando el siguiente debe comenzar, la política de concurrencia determina el comportamiento. Allow permite múltiples Jobs simultáneos, Forbid los evita y Replace detiene el anterior y comienza el nuevo.

Etiquetas: ReplicaSet Deployment DaemonSet Job CronJob

Publicado el 7-6 22:43