Cero Downtime en Kubernetes: Guía para Deploys Sin Errores

Kubernetes DevOps Zero Downtime Deploy
8 minutos de lectura

Hay pocos momentos más tensos en la vida de un equipo de ingeniería que el deploy a producción. Alguien ejecuta el comando, todos miran el canal de Slack, y durante unos segundos nadie respira. ¿Funcionó? ¿Se cayó algo? ¿Los usuarios lo notaron?

Si tu equipo siente esa tensión cada vez que despliega, hay un problema. Los deploys no deberían dar miedo. En un setup de Kubernetes bien configurado, podés desplegar una nueva versión de tu aplicación sin que ningún usuario note que algo cambió. Cero errores 502. Cero conexiones cortadas. Cero downtime.

Kubernetes no te da zero downtime por defecto. Te da las herramientas para lograrlo. Configurarlas correctamente es tu responsabilidad.

🔍Cómo funciona un deploy en Kubernetes por dentro

Cuando ejecutás un helm upgrade o un kubectl apply, el Rolling Update sigue una coreografía precisa:

01
Kubernetes crea un pod nuevo con la versión actualizada de tu aplicación.
02
Espera a que el pod pase los health checks y esté en estado “Ready”.
03
Una vez listo, empieza a enviarle tráfico al pod nuevo.
04
Simultáneamente, marca un pod viejo para terminar y deja de enviarle tráfico.
05
El pod viejo recibe SIGTERM y tiene un período de gracia para terminar lo que estaba haciendo.
06
Repite el ciclo pod por pod hasta que el 100% corre la versión nueva.

Dos parámetros controlan cómo se hace esa transición:

maxUnavailable
recomendado: 0
Cuántos pods pueden estar fuera de servicio simultáneamente. Con 0, nunca se baja un pod viejo hasta que uno nuevo esté listo — la opción más conservadora.
maxSurge
recomendado: 1+
Cuántos pods extra puede crear Kubernetes por encima del número deseado. Permite crear el pod nuevo antes de bajar el viejo, sin perder capacidad nunca.
La combinación ideal

maxUnavailable: 0 + maxSurge: 1 — nunca bajés un pod viejo hasta que el nuevo esté listo, y podés crear pods extras temporalmente para lograrlo. Más lento y usa más recursos durante el deploy, pero garantiza que la capacidad nunca baje del 100%.

// 01

❤️No tener readiness probes (o tenerlos mal)

Este es el error más común y el más impactante. El readiness probe le dice a Kubernetes: “este pod está listo para recibir tráfico”. Sin él, Kubernetes asume que el pod está listo en el momento que el container arranca — no cuando tu aplicación realmente está lista.

El problema

La mayoría de las aplicaciones necesitan unos segundos (a veces más) para levantar — cargar configuración, conectarse a la base de datos, calentar caches. Si Kubernetes empieza a enviar tráfico antes de que todo esto termine, los primeros usuarios que caigan en el pod nuevo van a recibir errores 503, conexiones rechazadas o timeouts.

La solución

Configurá un readiness probe apuntando a un endpoint que valide que la aplicación genuinamente está lista — incluyendo conexiones a dependencias críticas como la base de datos. No solo que el proceso está corriendo.

Si tu app tarda significativamente en arrancar (Spring Boot, modelos de ML, caches grandes), sumá un startupProbe para que Kubernetes no la marque como muerta mientras levanta.

// 02

🛑No manejar el SIGTERM correctamente

Cuando Kubernetes decide terminar un pod viejo, le envía SIGTERM. Este es un aviso: “terminá lo que estás haciendo, tenés X segundos antes del SIGKILL”. El problema es que muchas aplicaciones no lo manejan y simplemente mueren, cortando cualquier request en vuelo.

El impacto

El usuario que tenía un request en proceso recibe un error. Si era un request de pago, una operación de escritura o una transacción, las consecuencias pueden ser graves. Cada deploy con SIGTERM sin manejar es una ventana de potencial corrupción de datos.

Para zero downtime real, tu aplicación necesita implementar graceful shutdown:

  • Escuchar la señal SIGTERM y dejar de aceptar conexiones nuevas.
  • Terminar los requests que ya están en vuelo.
  • Cerrar conexiones a bases de datos y servicios externos de forma limpia.
  • Recién entonces, terminar el proceso.
Configuración de Kubernetes

Ajustá terminationGracePeriodSeconds para darle a tu app tiempo suficiente. El default de 30 segundos puede no ser suficiente para algunas aplicaciones con transacciones largas o cierres de conexiones complejos.

// 03

⏱️La ventana de muerte entre SIGTERM y desregistración

Este es el gotcha más sutil y el que menos equipos conocen. Cuando Kubernetes decide terminar un pod, dos cosas pasan al mismo tiempo pero de forma asincrónica:

acción A
El pod recibe SIGTERM para que empiece a apagarse.
acción B
Kubernetes le dice al Service que deje de enviarle tráfico a ese pod.
El problema

Estas dos acciones no están sincronizadas. Tu app puede recibir SIGTERM y empezar a cerrarse, pero el Service todavía no sabe que ese pod está saliendo. Durante esos milisegundos — a veces segundos — el Service sigue enviando requests nuevos a un pod que ya está muriendo.

Los errores son intermitentes y casi imposibles de reproducir en desarrollo porque dependen del timing exacto de la propagación de red.

La solución: preStop hook con sleep

Agregá un preStop hook con un sleep de 3 a 10 segundos. Este delay le da tiempo al sistema de networking de Kubernetes para propagar el cambio antes de que tu aplicación empiece a cerrarse. Es contraintuitivo — estás retrasando el shutdown a propósito — pero es necesario para evitar requests perdidos.

// 04

🔢No tener suficientes réplicas

Si tu servicio corre con 1 o 2 réplicas y hacés un Rolling Update, la matemática no da. Con una sola réplica, Kubernetes necesita matar el pod viejo para crear el nuevo. Durante ese intercambio, hay un momento donde potencialmente ningún pod está listo.

El riesgo con pocas réplicas

Con 2 réplicas y maxUnavailable: 1, durante el deploy tenés un solo pod sirviendo toda la carga mientras el otro se reemplaza. Si ese pod no puede manejar toda la carga solo, tus usuarios van a experimentar degradación o timeouts.

El mínimo para zero downtime

Al menos 3 réplicas en cualquier servicio que reciba tráfico de usuarios. Esto le da a Kubernetes suficiente margen para rotar pods sin perder capacidad total. Complementá con un Pod Disruption Budget (PDB) para evitar que Kubernetes mate demasiados pods al mismo tiempo durante operaciones de mantenimiento.

// 05

🚀El pipeline de CI/CD que no espera el rollout

Un error frecuente en pipelines: asumir que el deploy terminó cuando helm upgrade retorna éxito. Helm retorna éxito cuando el manifiesto se aplica, no cuando los pods están listos.

El problema

Si tu pipeline reporta “deploy exitoso” en el momento que Helm termina, puede estar mintiendo. Los pods nuevos todavía están levantando, los readiness probes todavía están fallando, y la versión vieja todavía sirve tráfico. Si algo sale mal, no te vas a enterar hasta que los usuarios empiecen a reportar errores.

  • Ejecutá kubectl rollout status después del deploy — espera activamente a que el Rolling Update complete y todos los pods nuevos estén en estado Ready.
  • Configurá rollback automático si el rollout no completa en un tiempo razonable o si los readiness probes fallan repetidamente.
  • Definí un timeout explícito para el rollout — si no completa en X minutos, algo salió mal y hay que actuar.
// 06

🗺️Rolling Update no es la única estrategia

El Rolling Update es la estrategia por defecto, pero no la única. Dependiendo del caso podés considerar:

Blue / Green
Más recursos
Levantás el set completo de pods nuevos antes de cortar el tráfico. Rollback instantáneo. Requiere el doble de recursos durante el deploy.
Canary
Más complejidad
Desplegás en un porcentaje pequeño de pods y monitoreás antes de escalar. Requiere Argo Rollouts o Flagger para gestión automática.
Checklist completo — Zero Downtime Deploy
Configuración Qué hace Capa
En tu Deployment de Kubernetes
maxUnavailable: 0 Nunca baja pods viejos antes de tener uno nuevo listo K8s
maxSurge: 1+ Permite pods extras temporales durante el deploy K8s
réplicas ≥ 3 Margen suficiente para rotar pods sin perder capacidad Crítico
readinessProbe Tráfico solo cuando la app está genuinamente lista Crítico
livenessProbe Detecta pods vivos pero atascados (deadlock, leak) K8s
startupProbe Tiempo extra para apps con startup lento K8s
preStop sleep 3–10s Tiempo para propagar la desregistración del Service Crítico
terminationGracePeriod Tiempo suficiente para el graceful shutdown completo K8s
PodDisruptionBudget Protege contra bajas masivas en mantenimiento de nodos K8s
En tu aplicación
Manejo de SIGTERM Para de aceptar conexiones, termina requests en vuelo Crítico
Health endpoint Devuelve 200 solo cuando la app puede servir correctamente App
En tu pipeline de CI/CD
rollout status wait Espera a que todos los pods nuevos estén en Ready CI/CD
Rollback automático Revierte si el rollout falla o los probes fallan repetidamente CI/CD

Zero downtime debería ser el default, no un logro

Desde SleakOps, los workloads se despliegan con todas estas configuraciones aplicadas por defecto — Rolling Update, probes, graceful shutdown, preStop hook. No necesitás descubrir cada gotcha por tu cuenta.

Conocé SleakOps →

¿Listo para optimizar tu nube?

Agenda una demo con uno de nuestros expertos para mostrarte cómo Sleakops puede transformar tu operación en la nube.

Artículos relacionados