Implementar servicios de nodo con DaemonSets de Kubernetes

KubernetesBeginner
Practicar Ahora

Introducción

Algunos componentes de software deben ejecutarse una vez en cada nodo elegible, en lugar de utilizar un número fijo de réplicas. Los recopiladores de registros, los agentes de supervisión y los componentes de red suelen utilizar DaemonSets para este tipo de distribución orientada a nodos.

Etiquetarás el nodo preparado, implementarás un informador de nodos, rastrearás su propiedad, cambiarás la elegibilidad del nodo y realizarás una actualización progresiva. El laboratorio de un solo nodo permite observar fácilmente la regla de distribución, manteniendo el mismo comportamiento del controlador que se utiliza en clústeres más grandes.

La pregunta clave durante este laboratorio no es «¿cuántas réplicas deben ejecutarse?», sino «¿qué nodos son elegibles?». Un DaemonSet responde continuamente a esa pregunta y crea un Pod en cada nodo coincidente. En este entorno hay un solo nodo, por lo que cada cambio de elegibilidad produce claramente un resultado de uno a cero o de cero a uno.

Marcar un nodo elegible

En este paso, añadirás una etiqueta específica al nodo. Las etiquetas describen atributos de los nodos que los controladores pueden utilizar para seleccionarlos.

Comienza mostrando el nodo y sus etiquetas actuales. La salida es extensa, así que no intentes memorizarla; solo necesitas reconocer que las etiquetas son datos clave-valor asociados al objeto Node.

cd /home/labex/project/daemonset-workloads
kubectl get nodes --show-labels

Añade la nueva etiqueta. La opción --overwrite no es necesaria aquí porque la configuración inicial eliminó cualquier valor anterior, pero kubectl label te avisará si ya existe un valor en conflicto:

kubectl label node labex-v135 practice-tier=operations
kubectl get node labex-v135 -L practice-tier

-L practice-tier añade esa etiqueta como una columna de la tabla. Ahora el nodo se anuncia como elegible para el agente de operaciones de práctica.

El segundo comando ofrece un resultado más concreto que la línea muy extensa de --show-labels:

NAME         STATUS   ROLES           VERSION   PRACTICE-TIER
labex-v135   Ready    control-plane   v1.35.5   operations

PRACTICE-TIER=operations es la evidencia que necesitas. La etiqueta no ejecuta nada por sí sola; adquiere significado cuando una carga de trabajo la selecciona en el siguiente paso.

Implementar un DaemonSet

En este paso, crearás un DaemonSet dirigido a los nodos que tengan la nueva etiqueta.

Antes de escribirlo, interpreta el manifiesto como tres decisiones relacionadas. Tanto el selector como la etiqueta del Pod utilizan app: node-reporter, lo que permite al controlador reconocer sus Pods. Después, nodeSelector limita la elegibilidad a los nodos etiquetados con practice-tier=operations. Por último, la API Downward copia el valor de spec.nodeName del Pod seleccionado en el contenedor como NODE_NAME.

El bucle mantiene activo el agente de demostración. Un DaemonSet real podría ejecutar un recopilador de registros o un agente de supervisión.

cat <<'EOF' > node-reporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-reporter
  namespace: practice-daemon
spec:
  selector:
    matchLabels:
      app: node-reporter
  template:
    metadata:
      labels:
        app: node-reporter
    spec:
      nodeSelector:
        practice-tier: operations
      containers:
        - name: reporter
          image: busybox:1.36
          imagePullPolicy: IfNotPresent
          command: ["sh", "-c", "while true; do echo node=${NODE_NAME} version=v1; sleep 15; done"]
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
EOF

Crea el espacio de nombres, aplica el archivo y espera a que finalice el despliegue progresivo del DaemonSet:

kubectl create namespace practice-daemon
kubectl apply -f node-reporter.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl get daemonset,pods -n practice-daemon -o wide

La API Downward, mediante fieldRef, expone el nombre del nodo programado sin codificarlo directamente. En este clúster de un solo nodo, los recuentos deseado, actual y listo deberían ser todos iguales a uno.

El nombre del Pod contiene un sufijo generado, pero la columna NODE debería mostrar labex-v135. Esto demuestra directamente que la regla de elegibilidad y el resultado de la programación coinciden.

En el clúster de prueba de un solo nodo, las columnas importantes se veían así:

NAME            DESIRED   CURRENT   READY   NODE SELECTOR
node-reporter   1         1         1       practice-tier=operations

NAME                  READY   STATUS    NODE
node-reporter-...      1/1     Running   labex-v135

Lee la primera fila de izquierda a derecha: un nodo coincide con el selector, existe un Pod y ese Pod está listo. En un clúster más grande, estos recuentos aumentarían según el número de nodos elegibles.

Observar la elegibilidad y la propiedad

En este paso, demostrarás que la cantidad de Pods del DaemonSet depende de la elegibilidad de los nodos, no de un campo de réplicas.

Primero, captura una línea base saludable. Las columnas personalizadas relacionan el Pod generado con el DaemonSet, y los registros demuestran que la API Downward proporcionó el nombre del nodo:

kubectl get pods -n practice-daemon -l app=node-reporter -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,OWNER:.metadata.ownerReferences[0].kind,READY:.status.containerStatuses[0].ready'
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

La tabla de propiedad y los registros deberían parecerse a esto:

POD                   NODE         OWNER       READY
node-reporter-...     labex-v135   DaemonSet   true
node=labex-v135 version=v1

El campo OWNER demuestra que se trata de un Pod administrado por un controlador. Los registros demuestran que NODE_NAME provino del spec.nodeName real del Pod y no de un valor codificado manualmente.

Elimina temporalmente la etiqueta y observa cómo desaparece el Pod:

kubectl label node labex-v135 practice-tier-
kubectl get daemonset node-reporter -n practice-daemon
kubectl wait --for=delete pod -n practice-daemon -l app=node-reporter --timeout=60s

Un signo - al final elimina una clave de etiqueta. Restaura la elegibilidad y espera a que el controlador cree un Pod de reemplazo:

Después de eliminar la etiqueta, el DaemonSet muestra brevemente la siguiente relación estable:

NAME            DESIRED   CURRENT   READY
node-reporter   0         0         0

Esta es una respuesta normal a un cambio en la elegibilidad, no un error. Ningún nodo coincide actualmente con el nodeSelector del DaemonSet, por lo que el recuento deseado correcto es cero.

kubectl label node labex-v135 practice-tier=operations
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s

Compara el nombre del Pod antes y después del cambio de etiqueta. El reemplazo tiene una identidad de Pod nueva, mientras que el nombre del DaemonSet y el comportamiento deseado permanecen iguales. Esto es la reconciliación en acción.

Implementar una actualización del DaemonSet

En este paso, actualizarás el manifiesto guardado y observarás cómo el DaemonSet reemplaza al agente del nodo. Mantener sincronizados el archivo y el objeto activo hace que el estado deseado pueda reproducirse.

Primero crea una copia de trabajo con cp. Después, utiliza el mismo patrón de edición de texto directa presentado en Kubernetes para principiantes: sed -i 's/old/new/' file reemplaza directamente el texto coincidente en el archivo, mientras que grep -n muestra la línea coincidente junto con su número para que puedas revisar el resultado antes de aplicarlo.

cp node-reporter.yaml node-reporter-v2.yaml
sed -i 's/version=v1/version=v2/' node-reporter-v2.yaml
grep -n 'version=' node-reporter-v2.yaml
kubectl apply -f node-reporter-v2.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl rollout history daemonset/node-reporter -n practice-daemon
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

El archivo copiado conserva el ejemplo original con v1 para facilitar la comparación. La sustitución cambia únicamente el texto de versión dentro del comando del contenedor; al aplicar el archivo actualizado, se modifica la plantilla del Pod, se crea una nueva revisión del controlador y se genera un Pod de reemplazo. Los registros ahora deberían contener version=v2.

rollout history confirma que Kubernetes registró una nueva revisión. Por tanto, los DaemonSets admiten actualizaciones controladas de plantillas, de forma similar a los Deployments, aunque el reemplazo se organiza en torno a los nodos elegibles y no a un número de réplicas.

La salida de prueba incluía dos revisiones y el nuevo mensaje de registro:

REVISION  CHANGE-CAUSE
1         <none>
2         <none>

node=labex-v135 version=v2

CHANGE-CAUSE=<none> solo significa que no se registró ninguna anotación descriptiva del cambio. La revisión 2, junto con version=v2 en los registros del Pod de reemplazo, son las pruebas útiles de que la actualización progresiva se realizó.

Resumen

Utilizaste etiquetas de nodo para controlar la elegibilidad de un DaemonSet, observaste la reconciliación de un Pod por cada nodo elegible, rastreaste la propiedad del controlador y ejecutaste una actualización progresiva del agente del nodo. Ahora puedes comparar los DaemonSets con los Deployments orientados a réplicas y los Jobs orientados a completar tareas.