Receta: Despliegue Blue-Green
Despliega sin interrupción usando ambientes blue-green, conmutación instantánea de tráfico y rollback automatizado.
Visión General
El despliegue blue-green es una estrategia de release que mantiene dos ambientes de producción idénticos: uno activo (blue) y otro inactivo (green). Las nuevas versiones se despliegan en el ambiente inactivo, se validan con smoke tests, y luego el tráfico se conmuta instantáneamente. Si surgen problemas, el rollback es una simple conmutación de tráfico, tomando segundos en lugar de horas.
Esta receta cubre implementaciones concretas — conmutación por configuración de Nginx, selectores de Service en Kubernetes y weighted routing de Route 53. Para las compensaciones estratégicas frente a rolling y canary, consulta la guía de estrategias de despliegue; para el patrón abstracto, el patrón de despliegue blue-green.
Cuándo Usar
Usa este recurso cuando:
- El downtime durante despliegues es inaceptable (SLA > 99.9%). Consulta Health Check Endpoint para verificación de readiness.
- Necesitas capacidad de rollback instantáneo sin redeployar. Consulta Feature Flags para toggles instantáneos.
- Ejecutas migraciones de base de datos que deben ser retrocompatibles. Consulta Docker Compose Local Dev para testing local de migraciones.
- Validas nuevos releases contra tráfico real de producción vía canary routing. Consulta Istio Canary Deployment para shifting progresivo de tráfico.
Solución
Conmutación de Tráfico con Nginx (Bash)
#!/bin/bash
# Conmuta tráfico de blue a green
BLUE_IP="10.0.1.10"
GREEN_IP="10.0.1.11"
NGINX_CONF="/etc/nginx/sites-enabled/app"
# Actualizar upstream para apuntar a green
sed -i "s/server $BLUE_IP:8080/server $GREEN_IP:8080/" $NGINX_CONF
nginx -s reload
# Health check en green
if ! curl -sf http://$GREEN_IP:8080/health; then
# Rollback instantáneo
sed -i "s/server $GREEN_IP:8080/server $BLUE_IP:8080/" $NGINX_CONF
nginx -s reload
echo "Rollback completado"
exit 1
fi
Kubernetes Deployment con Service Switch
apiVersion: v1
kind: Service
metadata:
name: app-active
spec:
selector:
version: blue # Cambiar a "green" para conmutar
ports:
- port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-green
spec:
replicas: 3
selector:
matchLabels:
app: web
version: green
template:
metadata:
labels:
app: web
version: green
spec:
containers:
- name: app
image: myapp:v2.0.0
AWS Route 53 Weighted Routing
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "api.example.com",
"Type": "A",
"SetIdentifier": "green",
"Weight": 100,
"TTL": 60,
"ResourceRecords": [{"Value": "1.2.3.4"}]
}
}]
}'
Explicación
Cómo funciona:
- Ambiente blue sirve todo el tráfico de producción
- Ambiente green recibe el nuevo despliegue
- Smoke tests validan green (health checks, transacciones sintéticas)
- Conmutación de tráfico dirige a todos los usuarios hacia green
- Blue permanece caliente como target de rollback instantáneo
- Próximo deploy va a blue, los roles se intercambian
Compatibilidad de base de datos:
- Las migraciones deben ser retrocompatibles (agregar columnas, nunca eliminar)
- Blue debe tolerar el schema de green; green debe tolerar el schema de blue
- Usa feature flags para ocultar nuevas columnas de blue
Variantes
| Estrategia | Downtime | Velocidad de Rollback | Costo |
|---|---|---|---|
| Blue-Green | Cero | Instantáneo (segundos) | 2x infraestructura |
| Rolling | Cero | Lento (minutos) | 1x + surge |
| Canary | Cero | Medio (minutos) | 1x + pequeño surge |
| Recreate | Alto | N/A | 1x |
Lo que funciona
- Mantén blue caliente por un ciclo de deploy: No desmantelar hasta que el próximo despliegue tenga éxito
- Automatiza la conmutación: Las actualizaciones manuales de DNS son propensas a errores; usa pipelines CI/CD
- Monitorea durante la conmutación: Observa tasas de error, latencia y métricas de negocio por 5-10 minutos post-conmutación
- Usa sticky sessions con cuidado: Conmutar durante una sesión puede interrumpir conexiones stateful
- Comparte estado vía stores externos: Ambos ambientes deben acceder a las mismas bases de datos, caches y colas
Errores Comunes
- Blue/green stateful: Las sesiones almacenadas en memoria se pierden durante conmutaciones; usa Redis o JWT
- Configs diferentes: Blue y green deben tener variables de entorno idénticas excepto la versión
- Olvidar testear rollback: Un despliegue que no puede hacer rollback de forma segura no está listo para producción
- Conflictos de schema de base de datos: Cambios de schema breaking desplegados antes de que ambas apps sean compatibles
- Dejar ambientes viejos corriendo: Los ambientes no utilizados generan costos en la nube; automatiza la limpieza
Automatización en Producción
Pipeline CI/CD con GitHub Actions
# .github/workflows/blue-green.yml
name: Blue-Green Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to green
run: |
kubectl apply -f k8s/green-deployment.yaml
kubectl rollout status deployment/app-green --timeout=120s
- name: Smoke test green
run: |
GREEN_IP=$(kubectl get svc app-green -o jsonpath='{.spec.clusterIP}')
for i in $(seq 1 10); do
if curl -sf "http://$GREEN_IP:8080/health"; then
echo "Green healthy"
break
fi
sleep 5
done
- name: Switch traffic to green
run: |
kubectl patch svc app-active -p '{"spec":{"selector":{"version":"green"}}}'
- name: Verify production
run: |
sleep 30
if ! curl -sf https://api.example.com/health; then
kubectl patch svc app-active -p '{"spec":{"selector":{"version":"blue"}}}'
echo "Rollback triggered"
exit 1
fi
- name: Scale down blue
run: kubectl scale deployment app-blue --replicas=0
Estrategia de Migración de Base de Datos
import psycopg2
def expand_migrate(conn):
"""Fase 1: Expand — agregar nuevas columnas, mantener las viejas."""
with conn.cursor() as cur:
cur.execute("""
ALTER TABLE users
ADD COLUMN IF NOT EXISTS email_v2 VARCHAR(255);
""")
cur.execute("""
UPDATE users SET email_v2 = email;
""")
conn.commit()
def contract_migrate(conn):
"""Fase 2: Contract — remover columnas viejas después de decomisionar blue."""
with conn.cursor() as cur:
cur.execute("""
ALTER TABLE users DROP COLUMN IF EXISTS email;
""")
conn.commit()
# Secuencia de deploy:
# 1. Ejecutar expand_migrate (tanto blue como green funcionan)
# 2. Conmutar tráfico a green
# 3. Después de validación, ejecutar contract_migrate (solo green usa el nuevo schema)
Script de Monitoreo Post-Conmutación
#!/bin/bash
# monitor-post-switch.sh
DURATION=300 # 5 minutos
INTERVAL=10
END=$((SECONDS + DURATION))
while [ $SECONDS -lt $END ]; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health)
LATENCY=$(curl -s -o /dev/null -w "%{time_total}" https://api.example.com/health)
ERROR_RATE=$(curl -s https://api.example.com/metrics | grep error_rate | awk '{print $2}')
echo "$(date -Iseconds) status=$STATUS latency=${LATENCY}s error_rate=$ERROR_RATE"
if [ "$STATUS" != "200" ] || (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
echo "ALERT: Rollback"
kubectl patch svc app-active -p '{"spec":{"selector":{"version":"blue"}}}'
exit 1
fi
sleep $INTERVAL
done
echo "Monitoreo completo. Green está estable."
Optimización de Costos
- Escala blue hacia abajo entre deploys. Mantén blue en 1 réplica para ahorrar costos manteniendo capacidad de rollback:
kubectl scale deployment app-blue --replicas=1
- Usa spot instances para el ambiente idle. Green corre brevemente durante el deploy; córrelo en spot instances más baratas:
nodeSelector:
node-role.kubernetes.io/spot: "true"
- Cachéa la imagen Docker en todos los nodos. Pre-pull la nueva imagen para evitar startup lento durante la conmutación:
# Usar un DaemonSet para pre-pull
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: image-pre-puller
spec:
template:
spec:
initContainers:
- name: pull
image: myapp:v2.0.0
command: ["true"]
containers:
- name: pause
image: gcr.io/google_containers/pause
Lectura Adicional
- Kubernetes Services — conmutación de tráfico por selector
- Route 53 weighted routing — blue-green a nivel DNS
- Alias de Lambda — blue-green serverless
Ver También
- Guía de Despliegue Blue-Green — compensaciones estratégicas y planificación del rollout
- Patrón de Despliegue Blue-Green — el patrón abstracto
- Apagado Elegante — drenar conexiones antes de la conmutación
- Despliegue Canary con Istio — desplazamiento progresivo de tráfico
- Scripts ejecutables — conmutación Nginx, manifiestos K8s, workflow CI/CD y script de monitoreo
Preguntas frecuentes
¿Cuánto cuesta el despliegue blue-green en la práctica?
Aproximadamente el doble durante las ventanas de deploy: corres dos ambientes completos mientras ocurre la conmutación. Entre deploys, escala blue hacia abajo a una huella mínima (una sola réplica caliente sigue dándote rollback instantáneo) y el sobrecoste baja a unos pocos dólares al día.
¿Puedo usar blue-green con serverless?
Sí. Los alias de AWS Lambda, las etapas canary de API Gateway y los despliegues production/preview de Vercel implementan la misma idea: dos versiones coexisten mientras el tráfico se invierte. Pagas por petición en lugar de por instancia, así que el coste de "2x infraestructura" prácticamente desaparece.
¿Cuál es la diferencia entre blue-green y canary?
Blue-green conmuta el 100% del tráfico de una vez: cutover instantáneo, rollback instantáneo, pero una mala release golpea a todos los usuarios a la vez. Canary dirige un porcentaje pequeño primero y luego aumenta gradualmente: rollout más lento, radio de impacto menor. Blue-green encaja en sistemas que necesitan rollback de un solo comando; canary en sistemas donde quieres que datos de producción validen la release poco a poco.
¿Cómo manejo conexiones WebSocket de larga duración durante una conmutación?
Usa un período de drain. Deja de aceptar nuevas conexiones en blue, espera que las existentes se cierren (con un timeout), luego conmuta. Para conexiones que exceden el timeout, envía una señal de reconnect para que los clientes se reconecten a green.
¿Debo usar blue-green para microservicios?
Blue-green funciona bien para servicios individuales pero se vuelve costoso a nivel cluster. Para microservicios, usa canary deployments o feature flags en su lugar. Blue-green es mejor para apps monolíticas o servicios críticos que necesitan rollback instantáneo.
¿Cómo gestiono secretos entre blue y green?
Ambos ambientes deberían referenciar el mismo secret store (Vault, AWS Secrets Manager). Nunca dupliques secrets en configs específicas de entorno. Los valores de los secretos son idénticos; solo difiere la versión del código.
Recursos Relacionados
Estrategias de Despliegue: Blue-Green, Canary y Rolling
Guía práctica de estrategias de despliegue: rolling, blue-green, canary, shadow y feature flags. Minimiza el riesgo y el tiempo de rollback al liberar a producción.
DocPlantilla de Checklist Post-Deploy
Plantilla de checklist para verificar despliegues: health checks, smoke tests, validación de métricas y preparación de rollback antes de dar el visto bueno.
GuideGuía de Pipelines CI/CD: Del Commit a Producción
Guía práctica para construir pipelines CI/CD con GitHub Actions, gates de testing, estrategias de despliegue y procedimientos de rollback.
RecipeImplementar graceful shutdown y reinicios sin downtime
Cómo implementar graceful shutdown y reinicios sin downtime para servidores web, workers y contenedores
RecipeDespliegues Canary con Istio Service Mesh
Como usar el splitting de trafico de Istio para realizar despliegues canary seguros desplazando gradualmente usuarios entre versiones de aplicaciones
RecipeTraffic Mirroring para Testing en Producción
Replica tráfico de producción a ambientes de staging para testing realista, despliegues shadow y validación de performance sin impactar usuarios.