Cómo Realizar Actualizaciones Continuas Sin Interrupción (Zero-Downtime Rolling Updates) en Despliegues de Kubernetes
Introducción
En las arquitecturas modernas de microservicios, mantener la disponibilidad continua durante las actualizaciones de aplicaciones es un requisito innegociable. Los Despliegues de Kubernetes (Kubernetes Deployments) simplifican este proceso al ofrecer Actualizaciones Continuas (Rolling Updates) automatizadas, una estrategia diseñada para reemplazar incrementalmente las versiones antiguas de los Pods por otras nuevas.
Sin embargo, lograr un verdadero tiempo de inactividad cero (zero-downtime) requiere más que la configuración predeterminada de Kubernetes. Exige una coordinación cuidadosa entre el manifiesto del Despliegue, los endpoints de salud de la aplicación y el proceso de terminación elegante. Esta guía proporciona un enfoque integral y paso a paso para configurar los Despliegues de Kubernetes y garantizar que las actualizaciones de la aplicación sean fluidas e invisibles para el usuario final.
Cubriremos el papel fundamental de las sondas de preparación (readiness probes), cómo ajustar los parámetros de la estrategia de despliegue (maxSurge y maxUnavailable), y las mejores prácticas para la terminación de la aplicación con el fin de eliminar las interrupciones del servicio durante las transiciones de despliegue.
Prerrequisitos para el Tiempo de Inactividad Cero
Antes de configurar el manifiesto de Kubernetes, la aplicación subyacente debe adherirse a ciertos principios para soportar despliegues sin interrupción:
- Compatibilidad Retrógrada de la Aplicación (Application Backward Compatibility): Durante el corto período en el que tanto la versión antigua como la nueva de la aplicación se ejecutan simultáneamente, deben ser compatibles con los recursos compartidos (bases de datos, colas, cachés).
- Idempotencia: Las operaciones que podrían ser manejadas por ambas versiones deben ser repetibles sin efectos secundarios negativos.
- Terminación Elegante (Graceful Termination): La aplicación debe estar programada para reconocer la señal
SIGTERMenviada por Kubernetes y dejar de aceptar nuevas conexiones de manera elegante mientras finaliza las solicitudes en curso antes de salir.
Entendiendo la Estrategia de Actualización Continua de Kubernetes
Los Despliegues de Kubernetes (Kubernetes Deployments) tienen por defecto la estrategia RollingUpdate. Este método asegura que la versión antigua de la aplicación no se desactive por completo antes de que la nueva versión esté operativa, gestionando la transición mediante dos parámetros principales:
| Parámetro | Descripción | Impacto en el Tiempo de Inactividad Cero |
|---|---|---|
maxSurge |
Define el número máximo de Pods que se pueden crear por encima del número deseado de réplicas. Puede ser un número absoluto o un porcentaje (predeterminado: 25%). | Controla la velocidad del despliegue y garantiza que la capacidad aumente temporalmente. |
maxUnavailable |
Define el número máximo de Pods que pueden no estar disponibles durante la actualización. Puede ser un número absoluto o un porcentaje (predeterminado: 25%). | Crucial para el tiempo de inactividad cero. Establecerlo en 0% significa que no se terminarán los Pods que están prestando servicio hasta que los nuevos Pods estén completamente Ready (Preparados). |
Estrategia Recomendada para Tiempo de Inactividad Cero
Para la máxima disponibilidad, la mejor configuración a menudo es garantizar una pérdida de capacidad nula durante el tiempo de inactividad cero:
maxUnavailable: 0(Asegura que la capacidad nunca caiga).maxSurge: 1o25%(Permite que la capacidad exceda brevemente el objetivo, asegurando que un nuevo Pod esté listo antes de que se elimine uno antiguo).
Paso 1: Implementación de Sondas de Preparación (Readiness Probes)
La Sonda de Preparación (Readiness Probe) es el mecanismo más importante para garantizar actualizaciones sin interrupción. Kubernetes confía en esta sonda para determinar si un nuevo Pod está listo para recibir tráfico de usuario y si un Pod antiguo todavía está sirviendo tráfico activamente.
Liveness vs. Readiness (Disponibilidad vs. Preparación)
- Sonda de Disponibilidad (Liveness Probe): Indica a Kubernetes si el contenedor está saludable y funcional. Si falla, el contenedor se reinicia.
- Sonda de Preparación (Readiness Probe): Indica a Kubernetes si el contenedor está listo para servir solicitudes. Si falla, el Pod se elimina de los endpoints del Servicio asociado, desviando el tráfico hasta que esté listo.
Para las actualizaciones continuas, la Sonda de Preparación se utiliza para controlar la transición. Kubernetes no procederá a terminar un Pod antiguo hasta que un Pod recién creado pase satisfactoriamente su verificación de preparación.
# deployment.yaml excerpt
spec:
containers:
- name: my-app
image: myregistry/my-app:v2.0
ports:
- containerPort: 8080
# --- Readiness Probe Configuration ---
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15 # Time to wait before first probe attempt
periodSeconds: 5 # How often to perform the check
timeoutSeconds: 3
failureThreshold: 3 # Number of consecutive failures to mark Pod as not ready
# --- Liveness Probe Configuration (Standard Health Check) ---
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
Consejo: Asegúrese de que el endpoint
/health/readyde su aplicación devuelva un código de éxito (HTTP 200-299) solo cuando la inicialización, las conexiones a la base de datos y otras dependencias externas estén totalmente operativas.
Paso 2: Configuración de la Estrategia de Despliegue
Para exigir un verdadero tiempo de inactividad cero, configuramos explícitamente la estrategia de actualización continua para evitar cualquier caída en el número de réplicas disponibles.
En esta configuración, Kubernetes creará primero un nuevo Pod (maxSurge: 1). Una vez que el nuevo Pod pase su sonda de preparación, solo entonces Kubernetes terminará un Pod antiguo. Dado que maxUnavailable es 0, la capacidad del servicio nunca cae por debajo del número de réplicas objetivo.
# deployment.yaml excerpt
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-deployment
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
# Ensures capacity never drops below the desired replica count (4)
maxUnavailable: 0
# Allows one extra Pod to be created during the rollout
maxSurge: 1
template:
# ... container specification ...
Paso 3: Garantizar la Terminación Elegante
Incluso con sondas de preparación robustas, si la aplicación se apaga instantáneamente al recibir la señal de terminación, se corre el riesgo de perder solicitudes en curso.
Kubernetes sigue una secuencia de terminación específica:
- El Pod se marca como Terminando (
Terminating). - El Pod se elimina de los endpoints del Servicio (el tráfico deja de enrutarse hacia él).
- Se ejecuta el hook (gancho) de pre-parada (pre-stop hook) (si está definido).
- El contenedor recibe la señal
SIGTERM. - Kubernetes espera la duración definida por
terminationGracePeriodSeconds(predeterminado: 30 segundos). - Si el contenedor sigue ejecutándose, recibe una señal
SIGKILLno negociable.
Para garantizar un apagado elegante, la aplicación debe manejar SIGTERM, y el terminationGracePeriodSeconds debe ser lo suficientemente largo para que la aplicación finalice las solicitudes existentes.
# deployment.yaml excerpt, inside the container spec
terminationGracePeriodSeconds: 45 # Increased time for graceful shutdown
containers:
- name: my-app
image: myregistry/my-app:v2.0
lifecycle:
preStop:
exec:
# Example: Running a script to immediately drain connections
command: ["/bin/sh", "-c", "sleep 10"]
Mejor Práctica: El tiempo entre que el Pod falla su Sonda de Preparación (Paso 2) y recibe
SIGTERM(Paso 4) es crítico. Si su aplicación manejaSIGTERMcorrectamente, establecer unterminationGracePeriodSecondsligeramente más largo (por ejemplo, 45 o 60 segundos) previene terminaciones forzosas (hard kills).
Paso 4: Realización y Monitoreo de la Actualización
Una vez que su manifiesto de Despliegue incluye la estrategia optimizada y sondas robustas, realizar la actualización es sencillo.
-
Actualizar la Etiqueta de la Imagen: Modifique su manifiesto de despliegue para reflejar la nueva versión de la imagen (por ejemplo, de
v2.0av2.1). -
Aplicar la Configuración:
bash kubectl apply -f deployment.yamlAlternativamente, puede parchear la imagen directamente:
bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1 -
Monitorear el Estado del Despliegue: Observe cómo Kubernetes progresa a través de las etapas, verificando que el número de Pods listos nunca caiga por debajo del recuento deseado.
bash kubectl rollout status deployment/my-web-deployment -
Verificar la Disponibilidad del Pod: Observe el estado de los Pods para confirmar que los Pods antiguos (v2.0) se terminan de manera elegante solo después de que los nuevos Pods (v2.1) estén completamente listos.
bash kubectl get pods -l app=my-web-deployment -w
Consideraciones Avanzadas
Uso de Presupuestos de Interrupción de Pods (PDBs)
Mientras que una estrategia de despliegue gestiona las actualizaciones voluntarias, un Presupuesto de Interrupción de Pods (PDB) garantiza que un número mínimo de Pods estén disponibles incluso durante interrupciones no planificadas (por ejemplo, mantenimiento de nodos, actualizaciones de clúster). Aunque los PDBs no controlan directamente la velocidad de la actualización continua, actúan como una red de seguridad.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 75% # Ensure at least 75% of replicas are always available
selector:
matchLabels:
app: my-web-deployment
La Importancia del Retraso Inicial
Si su aplicación tarda en inicializarse (por ejemplo, cargando grandes archivos de configuración o estableciendo cachés), asegúrese de que el initialDelaySeconds en su Sonda de Preparación sea lo suficientemente largo. Si la sonda verifica demasiado pronto y falla, el Pod será marcado como insalubre y potencialmente se quedará atascado en un bucle de fallos (crash loop), deteniendo todo el despliegue.
Conclusión
Lograr verdaderas actualizaciones continuas sin interrupción en Kubernetes es una combinación de configuración robusta de la plataforma y desarrollo de aplicaciones disciplinado. Al aprovechar correctamente las Sondas de Preparación para señalar el estado operativo, ajustar la estrategia de Despliegue (maxUnavailable: 0) para mantener la capacidad e implementar manejadores de terminación elegantes, puede garantizar que las actualizaciones de la aplicación se realicen de manera fiable sin interrumpir el servicio a sus usuarios. Pruebe siempre su proceso de actualización a fondo en un entorno de staging para validar el período de gracia de terminación y la lógica de la sonda.