StackPractices
intermediate Por Mathias Paulenko

Runbook de Rollback de Despliegues

Runbook para revertir despliegues fallidos: triggers, comandos de kubectl/Helm/ArgoCD, rollback de migraciones de base de datos y checklists de verificación.

Temas: devops

Visión General

Cuando un despliegue rompe producción tienes minutos, no horas. Este runbook te da los criterios de decisión para saber cuándo revertir, los comandos exactos para cada estrategia de despliegue (kubectl, Helm, ArgoCD, blue-green, canary), las rutas de rollback de migraciones de base de datos y los pasos de verificación y comunicación para después del rollback. Cada procedimiento está listo para copiar y pegar — durante un incidente deberías estar ejecutando, no improvisando.

Este runbook cubre el procedimiento operativo de revertir un despliegue defectuoso. Para planificar la estrategia de despliegue en sí, consulta Despliegues Blue-Green y Canary; para incidentes centrados en migraciones, consulta el Runbook de Migración de Datos.

Cuándo Usarlo

Acude a este runbook cuando un despliegue degrada producción y necesitas la ruta segura más rápida de vuelta a un estado conocido:

  • La tasa de errores o la latencia se disparan justo después de un despliegue
  • Los health checks fallan en los pods nuevos
  • Una migración rompió el contrato de la aplicación
  • Un canary muestra métricas negativas y hay que abortarlo

No hagas rollback para cambios solo de configuración (corrige el ConfigMap y redespliega), para una funcionalidad que se puede desactivar con un feature flag (apágala), o cuando el despliegue “malo” solo expuso un bug que ya existía (fix-forward es más rápido y mantiene el historial lineal).

Una decisión antes de la tabla: el rollback no siempre es la respuesta correcta. Si el despliegue defectuoso es un bug pequeño y bien entendido con un arreglo a 15 minutos, fix-forward puede ser la opción de menor riesgo — evitas hacer rebotar producción dos veces. Revierte cuando el fallo es amplio, la causa no está clara o los usuarios están afectados; fix-forward cuando el defecto está aislado y puedes verificar el arreglo rápido. En duda durante un incidente en vivo, revierte — siempre puedes desplegar de nuevo cuando esté arreglado.

Elige la ruta de rollback que corresponde a cómo se publicó el cambio:

Método de despliegueRuta de rollbackQué revierte
kubectl apply / Deploymentkubectl rollout undo (§2)Solo la plantilla de pods — no cambios de Service, Ingress ni ConfigMap
Release de Helmhelm rollback (§3)Todos los recursos que rastrea la revisión del release
ArgoCD / GitOpsGit revert (§4.2)Lo que cambió el commit revertido — la traza de auditoría más limpia
Blue-greenCambio de tráfico de vuelta (§5)Solo el enrutado; ambas versiones siguen desplegadas
Canary (Argo Rollouts / manual)Abortar o escalar a cero (§6)La división de tráfico; la versión estable no se toca
Migración de base de datosFix-forward / down migration / snapshot (§7)Esquema y datos — la ruta más lenta y arriesgada

Antes de Empezar

Treinta segundos de verificación valen más que un segundo despliegue fallido:

  • Confirma tu contexto de kubectl y namespace — kubectl config current-context. Revertir el clúster equivocado es peor que no revertir.
  • Comprueba que tienes permisos — necesitas update/patch sobre deployments y, para Helm, acceso a los secrets del release. Descúbrelo ahora, no a mitad del incidente.
  • Conoce tu última versión buena — etiqueta los releases o mantén revisionHistoryLimit ≥ 10 en los Deployments para que la revisión que necesitas siga existiendo.
  • Haz un snapshot de la base de datos antes de despliegues arriesgados — si el release incluye una migración, un snapshot previo es el único deshacer real para cambios destructivos.
  • Desactiva el auto-sync en apps gestionadas por GitOps — si ArgoCD sincroniza automáticamente mientras reviertes, volverá a desplegar el estado defectuoso sin problema alguno.

1. Triggers de Rollback

El rollback es una decisión tomada bajo presión. La tabla de triggers existe para que esa decisión se tome antes del incidente, no durante — acuerda los umbrales con tu equipo por adelantado y codifícalos en las alertas siempre que sea posible.

1.1 Criterios de Trigger

Trigger                    | Severity | Action              | Timeline
───────────────────────────┼──────────┼─────────────────────┼──────────
Error rate > 5%            | Critical | Rollback immediately | < 5 min
Error rate > 1%            | High     | Investigate, prepare | < 15 min
P99 latency > 2x baseline  | High     | Rollback if trending | < 15 min
P99 latency > 5x baseline  | Critical | Rollback immediately | < 5 min
Health check failures      | Critical | Rollback immediately | < 5 min
OOM kills increasing       | High     | Rollback if trending | < 10 min
Customer complaints > 10   | High     | Investigate, prepare | < 15 min
Deployment job timeout     | Medium   | Investigate          | < 30 min
Database connection errors | Critical | Rollback immediately | < 5 min

1.2 Árbol de Decisión de Rollback

Mermaid flowchart TD diagram

El árbol es deliberadamente agresivo: revertir un despliegue que resultó estar bien te cuesta un redespliegue; no revertir uno malo te cuesta una caída.

2. Rollback de Deployment en Kubernetes

kubectl rollout undo revierte la plantilla de pods del Deployment a una revisión anterior. No revierte cambios en Services, Ingresses, ConfigMaps o Secrets aplicados en el mismo release — esos necesitan su propio kubectl apply con el manifiesto anterior.

Antes de empezar, asegúrate de que .spec.revisionHistoryLimit del Deployment es lo bastante alto para conservar la revisión que quieres (el valor por defecto es 10; si despliegas con frecuencia, la revisión buena puede haberse eliminado ya).

2.1 Rollback con kubectl

# Revisar el historial de rollout
kubectl rollout history deployment/my-app -n production

# Ver detalles de una revisión concreta
kubectl rollout history deployment/my-app -n production --revision=3

# Revertir a la revisión anterior
kubectl rollout undo deployment/my-app -n production

# Revertir a una revisión concreta
kubectl rollout undo deployment/my-app -n production --to-revision=3

# Comprobar el estado del rollout
kubectl rollout status deployment/my-app -n production

# Pausar el rollout (si es canary y hay que pararlo)
kubectl rollout pause deployment/my-app -n production

# Reanudar el rollout
kubectl rollout resume deployment/my-app -n production

2.2 Verificar el Rollback

# Comprobar la versión de imagen actual
kubectl get deployment my-app -n production -o jsonpath='{.spec.template.spec.containers[*].image}'

# Comprobar el estado de los pods
kubectl get pods -n production -l app=my-app -o wide

# Revisar logs de pods en busca de errores
kubectl logs deployment/my-app -n production --tail=50

# Revisar eventos por problemas del deployment
kubectl get events -n production --field-selector involvedObject.name=my-app --sort-by='.lastTimestamp'

# Ejecutar el health check
kubectl exec -it deployment/my-app -n production -- curl -s http://localhost:8080/health

3. Rollback de Helm

helm rollback restaura el release completo a una revisión anterior — a diferencia de kubectl rollout undo, revierte todos los recursos que rastrea el release, incluidos Services y ConfigMaps. Sigue sin tocar lo que está fuera del release: CRDs instalados aparte, datos escritos en volúmenes o recursos externos como registros DNS.

3.1 Comandos de Rollback de Helm

# Listar los releases de Helm
helm list -n production

# Revisar el historial del release
helm history my-app -n production

# Revertir a la revisión anterior
helm rollback my-app -n production

# Revertir a una revisión concreta
helm rollback my-app 5 -n production

# Revertir con timeout
helm rollback my-app 5 -n production --timeout 5m

# Verificar el rollback
helm status my-app -n production
kubectl get pods -n production -l app.kubernetes.io/instance=my-app

3.2 Rollback de Helm con Limpieza

Un rollback fallido suele significar recursos atascados, no un Helm roto — revisa los pods que no terminan y los secrets del release que hayan quedado en mal estado:

# Si el rollback falla, buscar recursos atascados
kubectl get all -n production -l app.kubernetes.io/instance=my-app

# Borrado forzado de pods atascados
kubectl delete pod <pod-name> -n production --force --grace-period=0

# Revisar PVCs pendientes
kubectl get pvc -n production -l app.kubernetes.io/instance=my-app

# Limpiar secrets de Helm de releases fallidos
kubectl get secrets -n production -l owner=helm,name=my-app
kubectl delete secret sh.helm.release.v1.my-app.v6 -n production

4. Rollback de ArgoCD

Con GitOps hay dos rutas: el rollback por CLI (rápido, imperativo) y el revert en Git (más lento, pero mantiene el estado deseado en Git — que es la razón de ser de GitOps). Prefiere el revert en Git cuando la presión inmediata lo permite.

Nota: argocd app rollback es imperativo — cambia el estado en vivo sin tocar Git. Con el auto-sync activo, Argo CD detectará el drift y volverá a desplegar el estado nuevo (el defectuoso), así que desactiva el auto-sync primero y sigue con un revert en Git en cuanto el incidente esté bajo control.

4.1 Rollback por CLI de ArgoCD

# Obtener el estado de la aplicación
argocd app get my-app

# Revisar el historial de sincronización
argocd app history my-app

# Revertir a la sincronización anterior
argocd app rollback my-app

# Revertir a una revisión concreta
argocd app rollback my-app 5

# Desactivar el auto-sync antes del rollback (si está activo)
argocd app set my-app --sync-policy none

# Ejecutar el rollback
argocd app rollback my-app 5

# Reactivar el auto-sync después del rollback
argocd app set my-app --sync-policy automated --auto-heal

4.2 Rollback de ArgoCD Basado en Git

# Rollback basado en Git — revertir el commit y hacer push
git revert <bad-commit-sha>
git push origin main

# ArgoCD detecta el cambio y sincroniza automáticamente (si el auto-sync está activo)
# Si el auto-sync está desactivado, sincronizar manualmente:
argocd app sync my-app

# Sincronización forzada si hace falta
argocd app sync my-app --force

5. Rollback de Despliegue Blue-Green

El rollback blue-green es un cambio de enrutado, no un redespliegue — el entorno antiguo sigue corriendo, así que revertir es casi instantáneo. Esa es la razón principal para pagar el coste de infraestructura doble. Una precondición que comprobar primero: el entorno blue tiene que seguir existiendo de verdad. Si tu pipeline destruye el color anterior tras un switch exitoso, el rollback se convierte en un redespliegue de la versión antigua — más lento, pero igual de seguro.

5.1 Switch Blue-Green

# Estado actual: blue está activo, green es el despliegue nuevo
# Para revertir: devolver el tráfico a blue

# Cambio del selector del Service de Kubernetes
kubectl patch service my-app -n production -p \
  '{"spec":{"selector":{"version":"blue"}}}'

# Verificar que el tráfico cambió
kubectl get svc my-app -n production -o yaml | grep selector -A 3

# Comprobar que los pods reciben tráfico
kubectl get pods -n production -l version=blue -o wide

# Escalar a cero el deployment green (tras confirmar que blue está sano)
kubectl scale deployment my-app-green -n production --replicas=0

5.2 Rollback con VirtualService de Istio

# Rollback: enrutar el 100% del tráfico de vuelta a blue
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: my-app
  namespace: production
spec:
  http:
    - route:
        - destination:
            host: my-app-blue
            port:
              number: 8080
          weight: 100
# Aplicar el VirtualService de rollback
kubectl apply -f virtualservice-rollback.yaml -n production

# Verificar el enrutado del tráfico
kubectl get virtualservice my-app -n production -o yaml

6. Rollback de Canary

El rollback de canary es una decisión de tráfico: dejar de mover tráfico a la versión nueva y que la estable vuelva a recibir el 100%. Con Argo Rollouts el controlador lo hace por ti cuando falla el análisis — define umbrales de tasa de errores y latencia en un AnalysisTemplate y el abort pasa a ser automático en lugar de una decisión del pager. Sin análisis automatizado, el procedimiento de abajo es manual y la tabla de triggers de la sección 1 son tus criterios de aborto.

6.1 Rollback de Canary con Argo Rollouts

# Comprobar el estado del rollout
kubectl argo rollouts get rollout my-app -n production --watch

# Abortar el canary y revertir a stable
kubectl argo rollouts abort my-app -n production

# Promover el canary a stable (si el canary va bien)
kubectl argo rollouts promote my-app -n production

# Reintentar el rollout tras un abort
kubectl argo rollouts retry my-app -n production

6.2 Rollback de Canary Manual

# Estado actual: 20% del tráfico en la versión nueva, 80% en la estable
# Para revertir: escalar la versión nueva a 0 y restaurar la estable al 100%

# Escalar a cero el deployment canary
kubectl scale deployment my-app-canary -n production --replicas=0

# Escalar el deployment estable
kubectl scale deployment my-app-stable -n production --replicas=10

# Actualizar el service para que apunte solo a stable
kubectl patch service my-app -n production -p \
  '{"spec":{"selector":{"track":"stable"}}}'

# Verificar
kubectl get endpoints my-app -n production
kubectl get pods -n production -l track=stable

7. Rollback de Migraciones de Base de Datos

Los rollbacks de base de datos son la parte más lenta y arriesgada — el código se revierte en segundos, los datos no. Si puedes revertir o no depende de cómo se diseñó la migración, así que el trabajo real ocurre antes del despliegue: prefiere expand-contract para cualquier cosa que elimine o renombre columnas.

El orden importa cuando la aplicación y el esquema cambian a la vez: si la versión antigua de la aplicación no puede correr contra el esquema nuevo, revierte primero la base de datos (o tumbarás también la versión antigua que funcionaba). Si el esquema nuevo es retrocompatible — que es lo que expand-contract te da por diseño — revierte primero la aplicación y arregla el esquema después, sin presión.

Para incidentes centrados en migraciones que van más allá de un cambio de esquema, usa el Runbook de Migración de Datos.

7.1 Estrategia de Rollback por Tipo de Migración

Tipo de migración     | Estrategia de rollback
──────────────────────┼──────────────────────────────────────────
Forward-only          | Sin rollback — escribir migración fix-forward
Reversible            | Ejecutar la down migration (inversa de up)
Expand-contract       | Revertir la fase contract, conservar el expand
Restaurar snapshot    | Restaurar desde backup (último recurso, pérdida de datos)

7.2 Rollback con Flyway

# Comprobar el estado de las migraciones
flyway -url=jdbc:postgresql://db:5432/mydb info

# Deshacer la última migración (solo Flyway Teams)
flyway -url=jdbc:postgresql://db:5432/mydb undo

# Para la edición community — escribir una migración fix-forward
# Crear V20260704_2__rollback_add_column.sql
-- Migración fix-forward para deshacer un cambio defectuoso
-- V20260704_1__add_status_column.sql añadió una columna que rompió la app
-- V20260704_2__remove_status_column.sql la revierte

ALTER TABLE orders DROP COLUMN IF EXISTS status;

7.3 Rollback con Liquibase

# Comprobar el estado de las migraciones
liquibase --url=jdbc:postgresql://db:5432/mydb status

# Rollback por número (últimos N changesets)
liquibase --url=jdbc:postgresql://db:5432/mydb rollbackCount 1

# Rollback por etiqueta
liquibase --url=jdbc:postgresql://db:5432/mydb rollback v2.3.0

# Rollback por fecha
liquibase --url=jdbc:postgresql://db:5432/mydb rollbackToDate 2026-07-04

7.4 Patrón Expand-Contract

Fase 1 — Expand (añadir columna nueva, conservar la vieja)
  ALTER TABLE orders ADD COLUMN status_new VARCHAR(20);

Fase 2 — Migrate (escritura dual a ambas columnas)
  -- La aplicación escribe en status y en status_new
  -- Backfill: UPDATE orders SET status_new = status WHERE status_new IS NULL;

Fase 3 — Contract (cambiar lecturas a la columna nueva, eliminar la vieja)
  -- La aplicación lee de status_new
  ALTER TABLE orders DROP COLUMN status;
  ALTER TABLE orders RENAME COLUMN status_new TO status;

Rollback:
  - Tras la Fase 1: DROP COLUMN status_new (sin pérdida de datos)
  - Tras la Fase 2: DROP COLUMN status_new (la columna vieja sigue intacta)
  - Tras la Fase 3: no se puede revertir — hay que re-añadir la columna y hacer backfill

7.5 Restauración de Snapshot (Último Recurso)

Restaurar un snapshot implica pérdida de datos para todo lo escrito después del snapshot — mide esa ventana antes de apretar el gatillo:

# Restaurar desde el snapshot previo al despliegue
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier myapp-db-rolled-back \
  --db-snapshot-identifier pre-deploy-snapshot-2026-07-04

# O usar point-in-time recovery
aws rds restore-db-instance-to-point-in-time \
  --source-db-instance-identifier myapp-db \
  --target-db-instance-identifier myapp-db-rolled-back \
  --restore-time 2026-07-04T09:00:00Z

8. Procedimientos Post-Rollback

El rollback no termina cuando la versión antigua está sirviendo — termina cuando has verificado la salud del servicio, avisado a los stakeholders y capturado lo necesario para el post-mortem. Saltarse la checklist de verificación es cómo los equipos acaban “revirtiendo” a una versión que estaba rota de otra manera.

8.1 Checklist de Verificación

- [ ] El health check de la aplicación pasa
- [ ] La tasa de errores vuelve al baseline (< 0.1%)
- [ ] La latencia P99 vuelve al baseline
- [ ] Todos los pods corriendo y listos
- [ ] Conexiones de base de datos sanas
- [ ] No hay OOM kills nuevos
- [ ] Los dashboards de monitoreo muestran patrones normales
- [ ] Las quejas de clientes paran o bajan
- [ ] Los logs no muestran errores nuevos
- [ ] Las alertas vuelven al estado normal

8.2 Acciones Post-Rollback

1. Verificar el rollback con la checklist anterior
2. Notificar a los stakeholders (Slack, email, status page)
3. Crear el ticket de incidente si aún no existe
4. Capturar la línea de tiempo (hora de deploy, detección, rollback)
5. Preservar logs y métricas para el post-mortem
6. NO redesplegar la misma versión sin un fix
7. Identificar la causa raíz del fallo
8. Escribir el fix y probarlo en staging
9. Programar la reunión de post-mortem en un plazo de 48 horas
10. Actualizar el runbook de despliegue con las lecciones aprendidas

8.3 Plantilla de Comunicación

[RESUELTO] Rollback de despliegue en producción — my-app

Línea de tiempo:
  - 14:00 UTC: Despliegue de v2.3.1 iniciado
  - 14:05 UTC: La tasa de errores subió al 8%
  - 14:07 UTC: Rollback iniciado
  - 14:10 UTC: Rollback completado, tasa de errores de vuelta al 0.1%

Impacto:
  - Los usuarios vieron errores 500 durante unos 10 minutos
  - ~5% de las peticiones fallaron durante el incidente
  - Sin pérdida ni corrupción de datos

Causa raíz (preliminar):
  - Configuración errónea del pool de conexiones de base de datos en v2.3.1

Acciones:
  - Corregir la configuración del pool de conexiones
  - Añadir un test de conexión a base de datos pre-despliegue
  - Actualizar el pipeline de CI para detectar este error de configuración

Estado actual:
  - Producción está corriendo v2.3.0 (versión estable anterior)
  - Todos los servicios están sanos
  - Próximo despliegue programado tras verificar el fix en staging

Lectura Adicional

Preguntas frecuentes

¿Con qué rapidez debería hacer rollback?

Inmediatamente cuando la tasa de errores supera el 5% o los health checks fallan — revierte primero, investiga después. Un rollback en Kubernetes tarda 2-5 minutos; el análisis de causa raíz tarda horas. Hazlo con la versión fallida corriendo en staging, no mientras los clientes ven errores.

¿Qué pasa si el propio rollback falla?

Borra a la fuerza los pods atascados (kubectl delete pod <name> --force --grace-period=0) y luego prueba un --to-revision concreto del historial de rollout. Si ninguna revisión funciona, fija directamente la última imagen buena conocida: kubectl set image deployment/my-app container=myorg/my-app:v2.3.0.

¿Se puede revertir una migración de base de datos?

Solo si se diseñó para ello. Las migraciones reversibles llevan script down; las forward-only necesitan una migración fix-forward; expand-contract se puede revertir antes de la fase contract pero no después. Los cambios destructivos (DROP TABLE, DELETE) solo se recuperan desde un backup — último recurso.

¿Debería usar despliegues blue-green o canary?

Blue-green es más simple y revierte al instante, pero necesita infraestructura doble. Canary mueve el tráfico gradualmente y puede auto-revertir según métricas, pero necesita maquinaria de división de tráfico (Istio, Argo Rollouts). Los servicios de producción con mucho tráfico favorecen canary; los servicios pequeños funcionan bien con blue-green.

¿Cómo evito que los despliegues malos lleguen a producción?

Apila las barreras: tests en CI, escaneo de seguridad, canary con análisis automatizado, health checks pre-despliegue y feature flags para desacoplar despliegue de release. Ninguna sustituye a un plan de rollback — reducen cuántas veces lo necesitas.