StackPractices
intermediate Por Mathias Paulenko

Checklist de Despliegue sin Downtime

Un checklist para garantizar que los despliegues en producción se completen sin interrumpir el servicio usando patrones de rollout seguros.

Descripción General

Un solo despliegue defectuoso puede dejar fuera de servicio un sistema crítico en segundos. Los despliegues sin tiempo de inactividad actualizan producción mientras los usuarios siguen conectados, pero solo funcionan cuando los health checks realmente controlan el tráfico, los cambios de base de datos son compatibles con ambas versiones del código, y el rollback es un procedimiento probado en lugar de una esperanza. Este checklist cubre toda la ventana de release: qué verificar antes de desplegar, cómo enrutar el tráfico durante el rollout y las señales exactas que deben activar un rollback.

Está orientado a despliegues que no pueden interrumpir el tráfico. Para una lista de verificación general de pre-release, consulta la Plantilla de Checklist de Despliegue.

El checklist asume Kubernetes o un orquestador comparable, pero las mismas puertas aplican a cualquier plataforma: demuestra que la versión nueva está sana antes de que reciba tráfico, mantén la versión antigua viva hasta que la nueva se haya ganado todo el tráfico, y haz que la ruta de rollback sea más corta que el tiempo que tardan los usuarios en notar una caída.

Cuándo Usarlo

  • Lanzar una nueva versión de un servicio de cara al usuario donde las peticiones caídas cuestan ingresos o confianza.
  • Desplegar migraciones de esquema o datos mientras el código antiguo y el nuevo conviven.
  • Cambiar load balancers, reglas de ingress u otra infraestructura que puede cortar la disponibilidad.
  • Introducir por primera vez una estrategia de rollout como canary o blue-green.
  • Desplegar antes de un pico de tráfico donde una caída parcial sería visible.

No lo uses para un job batch o una herramienta interna donde una ventana de mantenimiento es aceptable, ni para cambios de esquema destructivos que nunca fueron diseñados para ser compatibles hacia atrás — corrige primero la estrategia de migración.

Prerequisitos

  • Un pipeline de CI/CD que produce un artefacto etiquetado e inmutable sin pasos manuales.
  • Endpoints de health check que reportan el estado real de las dependencias, no solo que el proceso está vivo.
  • Un load balancer, ingress o service mesh que permita desplazar el tráfico gradualmente.
  • Migraciones de base de datos escritas para ser compatibles hacia atrás (expand-contract).
  • Una ruta de rollback documentada con un artefacto y estado de datos conocidos.
  • Dashboards y alertas que cubran tasa de errores, percentiles de latencia y métricas de negocio.
  • Un canal de comunicación acordado y un responsable on-call para la ventana de release.

El Checklist

Trabaja las siete fases en orden — cada una asume que la anterior pasó. El checklist está pensado para imprimirse o pegarse en un ticket de release; cada casilla sin marcar es una decisión deliberada que deberías poder defender en un postmortem.

1. Preparación Previa al Despliegue

  • El cambio está aprobado y documentado, con un responsable del despliegue y del on-call asignados.
  • El código está mergeado y el artefacto compilado, etiquetado e inmutable.
  • Los tests unitarios, de integración y de contrato pasan en CI.
  • Las migraciones de base de datos fueron revisadas para compatibilidad hacia atrás.
  • Los feature flags están configurados para poder desactivar el comportamiento nuevo sin redesplegar.
  • La capacidad cubre el tráfico esperado más el pico de instancias duplicadas durante el rollout.
  • Los dashboards y alertas están activos y enlazados en el ticket de release.
  • La rotación de guardia conoce la ventana de despliegue y la ruta de escalado.
  • Los pasos de rollback se probaron en staging en el último trimestre, no solo están escritos.
  • La comunicación al cliente está redactada si el cambio es visible para el usuario.

2. Configuración de Health Checks

CheckEndpointCriterio de ÉxitoAcción ante Fallo
Liveness/health/liveHTTP 200Reiniciar contenedor
Readiness/health/readyHTTP 200 y dependencias accesiblesDetener enrutado de tráfico
Startup/health/startupHTTP 200Retrasar rollout
Dependencias/health/depsBase de datos, caché y cola respondenAlertar y detener
Negocio/health/businessFlujo crítico devuelve el valor esperadoAvisar al on-call

Una sonda de readiness que devuelve 200 sin verificar la base de datos es la causa más común de despliegues “exitosos” que fallan inmediatamente para los usuarios. La sonda debe fallar cuando una dependencia está caída, aunque el proceso esté sano.

3. Selección de Estrategia de Rollout

EstrategiaCaso de UsoNivel de RiesgoVelocidad de Rollback
Rolling updateServicios sin estado, bajo riesgoBajoMedia (terminar pods nuevos)
Blue-greenSesiones con estado, releases predeciblesMedioRápido (revertir tráfico)
CanaryAlto riesgo, métricas mediblesMedioRápido (drenar canary)
Feature flagExposición gradual a usuariosBajoInstantáneo (desactivar flag)
A/B deploymentValidar comportamiento de usuarioMedioRápido (re-enrutar tráfico)

Elige canary cuando puedas definir una puerta de métricas, blue-green cuando las sesiones o cachés hagan riesgoso el tráfico con versiones mixtas, y rolling updates para servicios sin estado de bajo riesgo. La Guía de Despliegue Canary cubre el gating por métricas en profundidad; para dividir tráfico con Istio consulta Despliegue Canary con Istio.

4. Pasos de Ejecución del Despliegue

PasoAcciónVerificación
1Desplegar en staging y ejecutar smoke testsTests de staging pasan
2Desplegar canary o un subconjunto pequeñoHealth checks pasan, tasa de errores estable
3Monitorear métricas clave durante la duración del canaryLatencia, errores y métricas de negocio dentro de la línea base
4Aumentar el porcentaje de tráfico gradualmenteCada etapa pasa health checks y métricas
5Completar el rollout al 100%Todas las instancias sanas y sirviendo tráfico
6Validar endpoints de producciónSmoke tests y flujos críticos pasan
7Mantener la versión anterior disponible para rollbackRetener durante la ventana de rollback definida
8Confirmar que la ventana de rollback ha pasadoEliminar la versión antigua o actualizar el baseline

5. Seguridad en Migraciones de Base de Datos

  • Las migraciones son aditivas y funcionan con la versión anterior de la aplicación.
  • El código antiguo puede leer el esquema nuevo sin errores.
  • El código nuevo puede leer el esquema antiguo si hay que hacer rollback.
  • Los índices se crean de forma concurrente cuando el motor lo permite.
  • Las migraciones grandes se dividen en lotes suficientemente pequeños para no superar los timeouts de lock.
  • Los jobs de backfill y migración son idempotentes y reanudables.
  • Existe un script de rollback u operación compensatoria y está probado.
  • Los cambios de esquema se probaron en staging con volumen de datos similar al de producción.

6. Disparadores de Rollback

DisparadorUmbralAcción
Pico en tasa de errores> 0,5% durante 2 minutosPausar rollout e investigar
Aumento de latenciap99 > línea base + 30% durante 5 minutosRevertir tráfico
Caída en métrica de negocioConversión baja > 5%Rollback inmediato
Fallo de health check> 10% de instancias fallandoRollback inmediato
Alerta críticaCualquier incidente P1Rollback y avisar al on-call
Timeout del canaryLa etapa canary supera su duración sin pasarRollback del canary

Vincula estos umbrales a tus SLOs en lugar de copiarlos a ciegas. Un servicio con objetivo de disponibilidad del 99,9% tolera una quema de error budget menor que estos valores por defecto. Para el procedimiento de rollback en sí, ten abierto el Runbook de Rollback de Despliegues durante el release.

7. Validación Post-Despliegue

  • Los logs de la aplicación no muestran errores inesperados ni nuevos tipos de excepción.
  • La tasa de errores y la latencia se mantienen en la línea base durante al menos 30 minutos.
  • Las métricas de negocio están estables o mejorando.
  • Los feature flags están en el estado previsto.
  • Los recursos antiguos siguen disponibles hasta que cierre la ventana de rollback y luego se eliminan.
  • Se envía un resumen del despliegue al equipo con enlaces a los dashboards.
  • Cualquier incidencia encontrada queda registrada en el tracker con responsable.

Cómo Funciona

El despliegue sin downtime se apoya en tres pilares. La mecánica segura de rollout mantiene las versiones antigua y nueva sirviendo tráfico al mismo tiempo. Las señales de salud fiables le dicen al controlador de tráfico cuándo una instancia nueva está realmente lista. El rollback rápido reduce el radio de impacto cuando alguno de los dos primeros falla. El checklist existe porque el modo de fallo es siempre el mismo: un paso que “normalmente funciona” se omite bajo presión de tiempo, y justo en el release donde importaba, el servicio se cae.

El argumento económico es directo. Un canary al 10% que detecta una regresión la expone a una décima parte de tus usuarios durante unos minutos. La misma regresión enviada al 100% del tráfico de golpe se convierte en una caída completa, un tiempo de detección más largo y un rollback ejecutado bajo presión de incidente — exactamente las condiciones en las que los errores se multiplican. Medido en downtime total visible para el usuario, el camino por etapas es el rápido.

Configuración de Rolling Update en Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 3
      maxUnavailable: 0
  template:
    spec:
      containers:
        - name: api
          image: registry.example.com/api:v2.3.1
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 10
            failureThreshold: 3
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 15 && kill -SIGTERM 1"]
      terminationGracePeriodSeconds: 60

maxUnavailable: 0 mantiene todas las réplicas sirviendo mientras maxSurge: 3 levanta pods nuevos en paralelo. El hook preStop duerme antes del SIGTERM para que el kubelet tenga tiempo de quitar el pod de los endpoints — sin él, las peticiones en vuelo llegan a un pod que ya se está apagando.

Configuración de Canary con Argo Rollouts

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-gateway
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: { duration: 5m }
        - analysis:
            templates:
              - templateName: success-rate
            args:
              - name: service-name
                value: api-gateway
        - setWeight: 30
        - pause: { duration: 5m }
        - analysis:
            templates:
              - templateName: success-rate
            args:
              - name: service-name
                value: api-gateway
        - setWeight: 50
        - pause: { duration: 10m }
        - setWeight: 100
  selector:
    matchLabels:
      app: api-gateway
  template:
    metadata:
      labels:
        app: api-gateway
    spec:
      containers:
        - name: api
          image: registry.example.com/api:v2.3.1
          ports:
            - containerPort: 8080

Cada paso analysis ejecuta un AnalysisTemplate (aquí success-rate) contra tu proveedor de métricas; un análisis fallido aborta el rollout y devuelve el tráfico automáticamente. Ajusta pesos y pausas a tu volumen de tráfico — un canary al 10% necesita suficientes peticiones por minuto para que las métricas sean estadísticamente significativas.

Flujo de Rollout Canary

flowchart diagram: Desplegar canary 10%

Drenaje de Conexiones y DNS

Dos detalles rompen silenciosamente despliegues por lo demás limpios. Primero, el drenaje de conexiones: cuando el load balancer retira una instancia, mantén terminationGracePeriodSeconds por encima de la petición más larga que esperes — 60 segundos sirve para APIs HTTP típicas pero no para WebSocket o endpoints de streaming, donde debes enviar un frame de cierre del lado del servidor y esperar a que el contador de conexiones activas llegue a cero. En AWS ajusta el deregistration delay del target group; en GCP usa el connection draining timeout del backend service.

Segundo, el DNS. Si tu switch blue-green depende de DNS, baja el TTL del registro a 30-60 segundos al menos un día antes del cutover — los resolvers cachean agresivamente y un switch “instantáneo” puede tardar la vida del TTL antiguo para algunos clientes. Prefiere el enrutado ponderado en el load balancer o en el mesh siempre que sea posible, para que el switch no dependa del comportamiento del cliente.

Migraciones de Base de Datos con Expand-Contract

Expand-contract divide un cambio de esquema rompedor en tres despliegues seguros:

-- Fase 1 (expand): añadir la nueva forma junto a la antigua
ALTER TABLE orders ADD COLUMN total_cents BIGINT;
CREATE INDEX CONCURRENTLY idx_orders_total_cents ON orders(total_cents);

-- Fase 2 (migrate): dual-write desde la app, backfill por lotes
UPDATE orders SET total_cents = ROUND(total * 100)
 WHERE id BETWEEN :lo AND :hi AND total_cents IS NULL;

-- Fase 3 (contract): un despliegue posterior elimina la columna vieja
ALTER TABLE orders DROP COLUMN total;

Las reglas que lo hacen seguro: nunca renombres ni elimines una columna en el mismo release que despliega el código nuevo, mantén los backfills idempotentes y por lotes para que un job fallido pueda reanudarse, y crea los índices con CONCURRENTLY en Postgres para evitar locks de tabla. Ejecuta cada fase como un despliegue separado con su propia ventana de validación.

Runbook Canary Minuto a Minuto

TiempoAcciónPuerta
T-0Desplegar canary al 10% de pesoPods listos, sin pico de errores
T+5mRevisar tasa de errores, p99 y métricas de negocioTodo dentro de la línea base
T+10mEscalar al 30%El análisis pasa
T+15mRevisar métricas de nuevoTodo dentro de la línea base
T+20mEscalar al 50%El análisis pasa
T+30mEscalar al 100%El análisis pasa
T+60mChecklist de validación post-despliegueTodos los ítems marcados
T+24hCerrar la ventana de rollback, eliminar versión antiguaSin incidentes registrados

Trata las puertas como paradas duras, no como sugerencias — si una métrica cruza un umbral disparador, pausa o haz rollback e investiga antes de reintentar.

Variantes

  • Checklist de rolling update en Kubernetes: readiness probes, maxSurge, maxUnavailable y pod disruption budgets.
  • Checklist de blue-green: mecánica del switch de tráfico, compatibilidad de base de datos y retención de versiones.
  • Checklist de canary: umbrales de métricas, pesos de tráfico progresivos y puertas de rollback automático.
  • Checklist de despliegue serverless: versionado de funciones, enrutado por alias y gestión de stages de API Gateway.
  • Checklist de despliegue con base de datos intensiva: compatibilidad de esquema, orden de migraciones y scripts de rollback probados.
  • Checklist de despliegue móvil o de cliente: rollout por fases, gestión de actualización forzada y compatibilidad de API.

Lo que Funciona

  • Mantén los despliegues pequeños y frecuentes — un diff de 20 líneas es más fácil de revertir que uno de 2.000.
  • Mantén los cambios de base de datos legibles tanto por la ruta de código antigua como por la nueva.
  • Usa health checks que verifiquen dependencias reales, no solo que el proceso está vivo.
  • Automatiza el rollback sobre umbrales de métricas en lugar de depender de que alguien mire un dashboard.
  • Monitorea métricas de negocio junto a las técnicas; un despliegue puede pasar todos los health checks y aun así romper el checkout.
  • Mantén un artefacto baseline conocido para que el rollback sea un redespliegue, no una recompilación.
  • Practica los rollbacks en staging o game days — un plan de rollback sin probar es una hipótesis.
  • Registra las decisiones y resultados del despliegue para que el checklist mejore después de cada incidente.

Errores Comunes

  • Tratar un health check HTTP 200 como prueba de que el servicio funciona.
  • Desplegar un cambio de esquema destructivo en el mismo release que el código que lo necesita.
  • Enviar el 100% del tráfico antes de validar las métricas del canary.
  • Empezar un despliegue sin una ruta de rollback probada.
  • Mirar solo la tasa de errores mientras la latencia p99 se triplica en silencio.
  • Limpiar la versión antigua antes de que cierre la ventana de rollback.
  • Desplegar en hora punta sin margen para la capacidad duplicada durante el rollout.
  • Confiar en DNS para un switch instantáneo mientras los clientes cachean el registro antiguo.

Troubleshooting

  • El canary pasa los health checks pero los usuarios ven errores: la sonda de readiness no está cubriendo la dependencia que falla. Añade la dependencia real a /health/ready y repite el rollout en staging.
  • El rollback termina pero la caída continúa: el cambio de esquema no era compatible hacia atrás, así que el código antiguo crashea contra el esquema nuevo. Restaura la compatibilidad primero y luego haz rollback — por eso existe expand-contract.
  • Los pods terminan con peticiones en vuelo: falta el hook preStop o la eliminación del endpoint, así que el pod muere antes de que el load balancer deje de enrutarle. Añade el hook de sleep-then-SIGTERM y revisa el retardo de propagación del ingress.
  • Las métricas del canary se ven bien pero el rollout al 100% falla: la muestra del canary era demasiado pequeña para sacar a la luz el modo de fallo, normalmente un límite de recursos o una ruta de caché fría que solo aparece a tráfico completo. Compara los perfiles de recursos del canary y de la flota completa.
  • El rollback de feature flag deja datos inconsistentes: el flag desactivó escrituras pero no lecturas, o al revés. Despliega los cambios de flag para que las rutas de lectura y escritura cambien juntas, y mantén el flag al menos un release después de la activación completa.

Lectura Adicional

Preguntas frecuentes

¿Cuál es la diferencia entre rolling y canary deployment?

Los rolling updates van reemplazando las instancias antiguas de forma gradual, unos pocos pods cada vez, hasta que toda la flota corre la versión nueva. Un canary despliega primero un subconjunto pequeño, valida métricas y luego aumenta gradualmente el tráfico hacia la versión nueva.

¿Cómo hacemos seguros los cambios de base de datos para zero downtime?

Usa cambios aditivos primero (añade columnas, tablas, índices), despliega código que lea el esquema antiguo y el nuevo, y luego elimina el esquema viejo en un release posterior. Este es el patrón expand-contract.

¿Cuándo debemos hacer rollback inmediatamente?

Haz rollback cuando los health checks fallan de forma generalizada, la tasa de errores dispara, las métricas críticas de negocio caen o salta una alerta P1. Un rollback rápido preserva la confianza del usuario y los ingresos.

¿Cómo gestionamos conexiones de larga duración durante el despliegue?

Las conexiones de larga duración (WebSockets, SSE, streams gRPC) necesitan un hook preStop para drenarse con elegancia, un timeout de draining en el load balancer acorde, y un terminationGracePeriodSeconds suficientemente alto para la conexión más larga esperada. En WebSockets, envía un frame de cierre del servidor antes de terminar y espera a que el contador de conexiones activas llegue a cero antes de forzar el kill de los pods.

¿Qué es el patrón expand-contract para migraciones de base de datos?

Expand-contract es un patrón de tres fases para cambios de esquema sin downtime. En la fase expand añades columnas o tablas nuevas manteniendo las viejas. En la fase migrate la aplicación escribe en ambas y un backfill rellena las filas históricas. En la fase contract, un despliegue separado elimina las columnas viejas. Cada fase se publica con su propia ventana de validación.

¿Cómo probamos los despliegues zero-downtime antes de producción?

Prueba en staging bajo carga generada que imite el tráfico de producción. Despliega mientras corre la carga y mide tasa de errores, latencia p50/p95/p99, conexiones caídas y tasa de peticiones exitosas. Prueba también el rollback bajo carga, y alerta cuando los rollouts de producción se desvíen de los resultados de staging.

¿Cómo gestionamos los feature flags durante el despliegue?

Despliega con el flag desactivado, verifica estabilidad y luego actívalo para el 1-5% de usuarios monitorizando 10-15 minutos. Sube por 25%, 50% y 100% con monitorización en cada etapa. Si aparecen problemas, desactiva el flag al instante en lugar de hacer rollback. Mantén el flag en el código al menos un ciclo de release tras la activación completa.

¿Qué monitorización necesitamos durante despliegues zero-downtime?

Monitoriza tasa de errores, latencia p99, tasa de éxito de health checks, progreso del rollout, reinicios de pods y métricas de negocio, cada una con umbral de alerta. Un dashboard de despliegue que superponga los eventos de release sobre las métricas de la aplicación hace obvia la causa de una regresión de un vistazo.