Introducción
Los controladores de Kubernetes son el corazón de la automatización del cluster. Su trabajo es simple: observar el estado actual, compararlo con el estado deseado y actuar para corregir diferencias. Sin embargo, cuando el caché interno de un controlador se desincroniza con la realidad del cluster, el resultado es impredecible. En producción, esto puede manifestarse como:
- Un Deployment que no escala pods porque el controlador cree que ya hay suficientes (aunque el schedulador los haya eliminado por falta de recursos).
- Un ReplicaSet que elimina pods críticos porque no detectó que el usuario los había marcado como «no terminables».
- Un DaemonSet que no despliega nodos nuevos porque su caché no recibió el evento de creación de un Node.
En Kubernetes 1.36, el equipo de SIG API Machinery aborda esta problemática con dos frentes:
- Mitigación de obsolescencia: Mecanismos para evitar que los controladores actúen con datos desactualizados.
- Observabilidad: Métricas y herramientas para detectar y diagnosticar estos problemas antes de que escalen a incidentes en producción.
Estas mejoras no son teóricas: están implementadas en componentes críticos como kube-controller-manager y disponibles para cualquier desarrollador que use client-go.
Qué ocurrió
El problema de fondo: el caché de controladores y la ventana de obsolescencia
Los controladores de Kubernetes usan un patrón común:
- Informer: Escucha eventos del API Server (creaciones, actualizaciones, eliminaciones) y actualiza un caché local (store).
- Cola de trabajo: Los eventos se encolan para su procesamiento asincrónico.
- Reconciliación: El controlador lee el caché, compara con el estado deseado, y aplica cambios.
El riesgo aparece cuando el caché queda desincronizado:
- Restart del controlador: Al reiniciarse, el informer debe reconstruir su caché haciendo un list inicial de todos los objetos relevantes. Durante este proceso (que puede durar segundos o minutos), el caché está vacío o incompleto.
- Caídas del API Server: Si el etcd o el API Server fallan, el caché no se actualiza hasta que se restablece la comunicación.
- Eventos fuera de orden: Si el API Server envía eventos en un orden distinto al real (por ejemplo, por latencia en la red o fallos intermitentes), el caché puede registrar un estado inconsistente.
En versiones anteriores a 1.36, estos escenarios podían llevar a que los controladores:
- Ignoraran cambios críticos (por ejemplo, un Pod que se marca como Unschedulable pero el controlador no lo detecta porque su caché está desactualizada).
- Tomaran acciones incorrectas (como eliminar pods que el usuario marcó como Terminating pero el caché no reflejó).
La solución en Kubernetes 1.36
El release 1.36 introduce dos componentes clave:
1. AtomicFIFO en client-go
El client-go (la biblioteca base para interactuar con el API Server) ahora soporta colas FIFO atómicas para procesar eventos en lotes. Esto evita inconsistencias cuando eventos llegan fuera de orden.
- Versión afectada: client-go v0.32.0+ (incluido en Kubernetes 1.36).
- Feature Gate:
AtomicFIFO(activo por defecto). - Implementación: Las colas ahora usan un algoritmo que garantiza que, al procesar un lote de eventos (como los iniciales de un list), se apliquen en un orden consistente con el resourceVersion del API Server.
Ejemplo de cómo verificar la versión actual del caché:
import (
"k8s.io/client-go/tools/cache"
)
store := informer.GetStore()
latestRV := store.LastStoreSyncResourceVersion()
fmt.Printf("Última versión de recurso sincronizada: %s\n", latestRV)2. Consistencia de controladores en kube-controller-manager
Cuatro controladores críticos ahora incorporan lógica para evitar acciones basadas en datos obsoletos:
| Controlador | Feature Gate | Descripción |
|---|---|---|