Comprendiendo DaemonSet en Kubernetes: Despliegue y Actualización

Un DaemonSet en Kubernetes asegura que una copia de un Pod específico se ejecute en todos los nodos del clúster, o en un subconjunto de ellos. Cuando un nuevo nodo se une al clúster, automáticamente se le asigna una instancia del Pod gestionado por el DaemonSet. De manera similar, si un nodo es eliminado, los Pods asociados a él se desvinculan. La eliminación de un DaemonSet resulta en la supresión de todos los Pods que ha creado.

Los casos de uso típicos para DaemonSet incluyen:

  • Implementación de servicios de almacenamiento distribuidos, como glusterd o ceph, en cada nodo.
  • Despliegue de agantes de recolección de logs, como fluentd o logstash, en todos los nodos.
  • Ejecución de agentes de monitorización en cada nodo, tales como Prometheus Node Exporter, collectd, el agente de Datadog o el agente de New Relic.

Es posible configurar múltiples DaemonSets para diferentes propósitos o con configuraciones variadas (por ejemplo, distintos requisitos de CPU/memoria para distintas arquitecturas de hardware), permitiendo una gestión granular de los servicios de fondo.

Definición de un DaemonSet

Al igual que con otros recursos de Kubernetes, un DaemonSet requiere los campos apiVersion, kind y metadata. El campo spec define el comportamiento deseado del DaemonSet.

El componente esencial dentro de spec es template, que es una plantilla de Pod. Esta plantilla comparte el esquema de un objeto Pod, pero carece de los campos apiVersion y kind. Los Pods definidos en la plantilla de un DaemonSet deben incluir etiquetas (labels) que permitan la selección por parte del DaemonSet. Además, la política de reinicio (RestartPolicy) para los Pods en la plantilla de un DaemonSet debe ser Always o no especificarse, asumiendo por defecto Always.

El selector de Pods (spec.selector) especifica qué Pods son gestionados por el DaemonSet. Este selector puede basarse en matchLabels o matchExpressions, permitiendo la definición de criterios de selección más complejos. Es imperativo que el selector definido en spec.selector coincida con las etiquetas especificadas en spec.template.metadata.labels. Si no se proporciona explícitamente, se asume que coinciden por defecto. Kubernetes previene la creación de Pods si sus etiquetas ya coinciden con el selector de un DaemonSet existente o son creados manualmente con el objetivo de ser gestionados por el DaemonSet.

Comunicación entre Pods de DaemonSet

Existen varias estrategias para la comunicación con los Pods gestionados por un DaemonSet:

  • Push: Los Pods del DaemonSet pueden enviar datos a otros servicios o bases de datos de métricas.
  • NodeIP y Puerto Fijo: Utilizando hostPort, los Pods pueden ser accesibles directamente a través de la IP del nodo y un puerto conocido. Esto requiere que los clientes tengan conocimiento de la lista de IPs de los nodos.
  • DNS y Headless Service: La creación de un Service sin clúster (Headless Service) con el mismo selector de Pods que el DaemonSet permite la discovery de los Pods del DaemonSet a través de registros DNS o del recurso endpoints.
  • Service: Un Service estándar, con el mismo selector de Pods, puede enrutar el tráfico a una instancia aleatoria del DaemonSet. Sin embargo, este método no permite acceder a un nodo específico.

Ejemplo de Despliegue: Redis y Filebeat con DaemonSet

A continuación, se muestra un ejemplo de cómo desplegar un servicio Redis y un agente Filebeat utilizando un DaemonSet. Ambos recursos pueden definirse en el mismo archivo YAML.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-cache
      tier: backend
  template:
    metadata:
      labels:
        app: redis-cache
        tier: backend
    spec:
      containers:
      - name: redis-container
        image: redis:6.2-alpine
        ports:
        - containerPort: 6379

---

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat-logging
  namespace: default
spec:
  selector:
    matchLabels:
      app: filebeat-agent
      environment: production
  template:
    metadata:
      labels: 
        app: filebeat-agent
        environment: production
    spec:
      containers:
      - name: filebeat-container
        image: elastic/filebeat:7.17.0
        env:
        - name: REDIS_HOST_ENV
          value: "redis-service.default.svc.cluster.local"
        - name: LOG_LEVEL_ENV
          value: "info"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: containerlogs
          mountPath: /var/lib/docker/containers
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: containerlogs
        hostPath:
          path: /var/lib/docker/containers

Para aplicar esta configuración:

kubectl apply -f deploy-redis-filebeat.yaml

Exponer el servicio Redis:

kubectl expose deployment redis-deployment --port=6379 --name=redis-service

Verificar el estado de los Pods:

kubectl get pods -o wide

Comprobar la configuración de Filebeat y la conexión a Redis:

kubectl exec -it <filebeat-pod-name> -- cat /etc/filebeat/filebeat.yml

Dentro del Pod de Redis, se puede verificar la conexión y la recepción de datos:

kubectl exec -it <redis-pod-name> -- redis-cli
127.0.0.1:6379> KEYS *

Actualización de DaemonSet

Los DaemonSets soportan dos estrategias de actualización:

  • OnDelete: La estrategia predeterminada por compatibilidad. Con esta opción, las nuevas versiones de los Pods solo se crean manualmente tras eliminar las instancias antiguas.
  • RollingUpdate: Con esta estrategia, al actualizar la plantilla del DaemonSet, los Pods antiguos se terminan y se crean nuevos Pods de manera controlada y automática.

Para habilitar la actualización continua, se debe configurar .spec.updateStrategy.type a RollingUpdate.

Para verificar la estrategia de actualización actual:

kubectl get daemonset <daemonset-name> -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'

Cualquier modificación en .spec.template de un DaemonSet con estrategia RollingUpdate iniciará el proceso de actualización. Esto se puede realizar mediante comandos declarativos (kubectl apply) o imperativos (kubectl edit, kubectl patch, o kubectl set image).

Ejemplo de actualización de la imagen del contenedor de Filebeat:

kubectl set image daemonset/filebeat-logging filebeat-container=elastic/filebeat:7.17.1

Observar el progreso de la actualización de los Pods:

kubectl get pods -w -l app=filebeat-agent

Durante una actualización RollingUpdate, se observa que los Pods antiguos se van terminando gradualmente a medida que se crean las nuevas instancias, asegurando una transición fluida del servicio.

Etiquetas: Kubernetes DaemonSet pods despliegue actualizacion

Publicado el 9-22 09:07