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.
Introducción
Una estrategia de despliegue es el proceso controlado de llevar código nuevo a producción minimizando el downtime y el coste de equivocarse. Un mal despliegue puede tumbar tu servicio, corromper datos o degradar la experiencia del usuario durante horas — la estrategia que elijas decide cuánto de ese riesgo absorbes y con qué rapidez puedes revertir.
Esta guía compara las cinco estrategias que realmente usarás en producción — recreate, rolling, blue-green, canary y shadow — más los feature flags como complemento del lado del release. Para cada una: cómo funciona, cuándo encaja y dónde duele. Las guías específicas de blue-green, canary y feature flags cubren cada una en profundidad.
Estrategias de Despliegue Comparadas
| Estrategia | Downtime | Riesgo | Rollback | Coste Infra | Ideal Para |
|---|---|---|---|---|---|
| Recreate | Parada total | Alto | Lento | 1× | Dev/test, no críticos |
| Rolling | Ninguno | Medio | Medio | ~1× | Stateless, cambios rutinarios |
| Blue-Green | Ninguno | Bajo | Instantáneo | 2× | Rollback instantáneo crítico |
| Canary | Ninguno | Muy bajo | Rápido | ~1.1× | Riesgo alto, releases graduales |
| Shadow | Ninguno | Muy bajo | N/A | 2× | Validar antes de exponer |
| Feature Flags | Ninguno | Mínimo | Instantáneo | 1× | Deploy ≠ release |
Prerequisitos: Lo Que Todo Despliegue Sin Downtime Necesita
Toda estrategia excepto recreate asume unas cuantas cosas ya resueltas. Si falta alguna, arréglala primero — ninguna estrategia te salva:
- Health checks que realmente fallen. Un endpoint
/healthque devuelve 200 mientras la app no alcanza la base de datos es peor que no tenerlo — el balanceador sigue enviando tráfico a un zombi. Configura liveness probes (“¿está corriendo?”) y readiness probes (“¿puede recibir tráfico?”) por separado. - Apagado ordenado. Las instancias deben drenar las peticiones en curso antes de morir, o los rolling updates cortarán peticiones a la mitad. Consulta la receta de graceful shutdown.
- Observabilidad antes del deploy. Necesitas dashboards y alertas de tasa de error, percentiles de latencia y tu una o dos métricas de negocio — con valores registrados antes de empezar. Comparar “ahora” contra “antes” es la única señal que vale.
- Cambios compatibles hacia atrás. Cualquier estrategia donde convivan dos versiones exige que ambas funcionen con los mismos contratos: esquemas de API, formatos de mensaje y esquemas de base de datos.
- Un pipeline automatizado. Si tu deploy es un
sshmanual, empieza por la guía de pipelines CI/CD y vuelve después.
Despliegue Recreate
Apagas la versión vieja por completo y luego arrancas la nueva. Nada convive.
Recreate es el kubectl delete y redespliegue de siempre — simple, barato y con downtime real. Todas las peticiones fallan entre el apagado y el arranque de la nueva versión. También garantiza cero desfase de versiones: solo corre una versión en cada momento, así que jamás te preocupas por código viejo leyendo datos nuevos.
Esa última propiedad hace de recreate la elección correcta para un conjunto sorprendente de servicios: sistemas stateful de instancia única donde dos versiones concurrentes son peligrosas de verdad (un job de migración que no debe correr dos veces, un servicio con líder que no puede partirse en dos), workers por lotes donde un reinicio es invisible, y pares de versiones que no comparten nada compatible. Úsalo en dev, staging y cualquier servicio donde 30 segundos de parada en una ventana programada no cuesten nada. Para servicios de cara al usuario con SLA, es una alarma, no una estrategia.
Rolling Deployment
Reemplaza instancias viejas por nuevas de forma gradual, manteniendo ambas vivas durante la transición:
# Rolling update en Kubernetes — la estrategia por defecto de Deployment
kubectl set image deployment/api api=myapp:v2.4.1
kubectl rollout status deployment/api
# Si sale mal
kubectl rollout undo deployment/api
En Kubernetes, maxSurge controla cuántos pods extra se levantan durante el rollout y maxUnavailable cuántos pueden caer. maxSurge: 1, maxUnavailable: 0 garantiza capacidad completa pero necesita margen para el pod extra; maxUnavailable: 1 es más rápido pero reduce la capacidad temporalmente.
Trade-off: durante el rollout, las versiones vieja y nueva conviven y comparten tráfico. Si v2 rompe un contrato de datos, las instancias v1 pueden fallar al leer datos escritos por v2 — las mismas reglas de compatibilidad que en blue-green, solo que de forma continua en vez de en un único cambio. El rollback tampoco es instantáneo: rollout undo repite el mismo proceso gradual hacia atrás, así que un despliegue ya al 80% tarda casi lo mismo en deshacerse. Para flotas pequeñas son segundos; para un servicio de 200 pods es un número real que conviene conocer antes de necesitarlo.
Blue-Green Deployment
Mantén dos entornos idénticos. Uno está vivo (blue), el otro en reposo (green). Despliega en green, pruébalo y cambia el tráfico en el balanceador — al instante, de forma atómica.
Antes: Usuarios → [Balanceador] → [Blue: v2.4.0 activo]
[Green: v2.4.0 en reposo]
Después: Usuarios → [Balanceador] → [Blue: v2.4.0 en reposo]
[Green: v2.4.1 activo]
# Esquema Terraform: blue-green detrás de un ALB de AWS
# El cambio de tráfico se hace repesando la regla del listener
resource "aws_lb_listener_rule" "app" {
action {
type = "forward"
forward {
target_group {
arn = aws_lb_target_group.blue.arn
weight = 100
}
target_group {
arn = aws_lb_target_group.green.arn
weight = 0 # subir a 100 en el cambio
}
}
}
}
La característica estrella es la velocidad del rollback: devolver el listener a blue tarda segundos y es un cambio puro de enrutado — sin migración de datos ni redespliegue. Eso convierte a blue-green en la única estrategia donde el “rollback” es genuinamente un no-op para el usuario: la versión vieja ya estaba corriendo y caliente.
El coste es pagar el doble de infraestructura — un setup blue-green sobre una flota de $10k/mes cuesta ~$20k. En clústeres grandes esto domina la decisión; muchos equipos solo levantan green durante la ventana de despliegue y lo tiran después, cambiando coste ocioso por complejidad. Un punto medio: autoescalar green de cero a total como parte del deploy y bajar blue a cero tras el periodo de observación — pagas 2× durante minutos u horas en vez de permanentemente.
Una advertencia más que golpea a los servicios stateful: blue-green funciona a nivel de aplicación, no de datos. Si mantienes dos bases de datos (una por color), las escrituras que entran en blue durante el periodo green se pierden al volver atrás. Mantén una base de datos compartida y gestiona los cambios con expand-contract — o no uses blue-green en ese servicio.
Consideraciones de Base de Datos
Blue-green solo funciona limpio cuando ambas versiones operan sobre la misma base de datos:
| Tipo de Cambio | ¿Compatible con Blue-Green? |
|---|---|
| Añadir columna (nullable) | Sí — el código viejo la ignora |
| Añadir columna (non-nullable) | No — el código viejo no puede insertar sin ella |
| Renombrar columna | No — el código viejo referencia el nombre antiguo |
| Eliminar columna | No — el código viejo puede seguir leyéndola |
| Añadir índice | Sí — ambas versiones se benefician |
Regla: blue-green exige cambios de esquema compatibles hacia atrás. Usa el patrón expand-contract: añade la columna nueva (expand), despliega código que lee y escribe ambas, y elimina la antigua (contract) en una release posterior. La receta de evolución de esquemas desarrolla el patrón completo.
Despliegue Canary
Dirige un porcentaje pequeño del tráfico real a la nueva versión, observa las métricas y sube solo si se comporta:
Paso 1: 1% → [Canary v2.4.1], 99% → [Estable v2.4.0]
Paso 2: 5% → [Canary v2.4.1], 95% → [Estable v2.4.0]
Paso 3: 25% → [Canary v2.4.1], 75% → [Estable v2.4.0]
Paso 4: 100% → [Canary v2.4.1 se vuelve estable]
Lo importante no es el porcentaje — es que una release mala solo daña al 1% de usuarios durante cinco minutos en vez del 100% hasta que lo notas. El análisis del canary es la parte difícil: necesitas umbrales definidos antes de desplegar y automatización que actúe sobre ellos. Mirar Grafana mientras pulsas “siguiente etapa” a mano es un canary solo de nombre.
# Flagger: canary automatizado con análisis de métricas y rollback automático
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: api
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api
service:
port: 80
analysis:
interval: 30s
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
- name: request-duration
thresholdRange:
max: 500
Si la tasa de error se dispara o la latencia cruza el umbral, Flagger devuelve el 100% del tráfico a la versión estable automáticamente — sin humanos de por medio. Argo Rollouts ofrece el mismo bucle con su CRD Rollout y AnalysisTemplate (ejemplo completo en la sección de escenario).
No necesitas un service mesh para un canary básico: en Kubernetes puro puedes aproximarlo con dos Deployments y enrutado por proporción de réplicas — tosco (el número de pods es un dial de porcentaje impreciso y se rompe con autoscaling), pero sirve para servicios de poca exigencia. Para enrutado real por porcentaje y cabeceras necesitas un mesh (Istio VirtualService, Linkerd) o un ingress con soporte de traffic split (anotaciones de NGINX ingress, target groups ponderados de AWS ALB).
Dónde Se Divide el Tráfico
Canary, blue-green y shadow necesitan una capa capaz de partir o conmutar el tráfico. Dónde viva esa capa determina lo que cada estrategia puede expresar:
- Balanceador de carga. Target groups ponderados (AWS ALB, backend services de GCP) o cambios por DNS (registros ponderados de Route53). Soporta porcentajes y cambio instantáneo para blue-green; sin segmentación por usuario, y la caché de DNS hace los cambios lentos — mantén los TTL bajos durante las ventanas de despliegue.
- Ingress / proxy inverso. Anotaciones
canary-*de NGINX ingress, HAProxy, Envoy. Enrutado por porcentaje y cabecera (x-canary: true), barato de operar, sin sidecars. Es el punto dulce para la mayoría de equipos. - Service mesh. Istio
VirtualService, Linkerd traffic split, Kuma. La opción más expresiva: porcentajes, cabeceras, cookies, reintentos, mirroring para shadow. Su coste también es real: un sidecar por pod y un control plane que mantener. - Nivel de aplicación. La app decide internamente — que es exactamente lo que son los feature flags, y por qué combinan tan bien con cualquier estrategia de infraestructura: el balanceador te mueve entre versiones, el flag te mueve entre comportamientos dentro de una versión.
Una progresión práctica que siguen la mayoría de equipos: empezar con rolling (integrado, gratis), añadir enrutado ponderado en el ingress o balanceador para blue-green y canary básico, y recurrir al mesh solo cuando el enrutado por cabeceras, el mirroring de shadow o los splits multi-clúster justifiquen el coste operativo.
Despliegue Shadow (Traffic Mirroring)
Envía a la nueva versión una copia del tráfico de producción mientras los usuarios solo ven respuestas de la versión estable. La instancia shadow procesa peticiones reales en paralelo; sus respuestas se descartan.
Shadow es la única estrategia con impacto cero al usuario y la mejor respuesta a “¿funciona de verdad bajo carga real?” — nuevos motores de búsqueda, motores de precios o una reescritura de la que dudas. Normalmente es un paso previo al canary: valida en shadow un día y luego empieza el canary.
Los inconvenientes: cuesta una segunda copia de la infraestructura de producción, jamás debe escribir en estado compartido (un shadow que cobra dos veces a los clientes es un evento de carrera — dirige las escrituras a un stub o a un esquema aparte), y el mirroring de tráfico requiere soporte del mesh o del balanceador — VirtualService mirroring de Istio, Envoy, o un setup de traffic mirroring en el upstream. Ten en cuenta también que el tráfico shadow duplica la carga de lectura sobre la base de datos: dimensiona para ello o reproduce el tráfico a ritmo reducido en servicios de muchas lecturas.
Feature Flags (Desacoplar Deploy de Release)
Despliega el código a producción pero mantenlo oculto tras un flag. Actívalo para usuarios o porcentajes concretos cuando estés listo — de forma independiente a cualquier despliegue.
# Feature flag estilo LaunchDarkly
if client.variation("new-checkout-flow", user_context, False):
return new_checkout.handle(request)
return old_checkout.handle(request)
| Usa Feature Flags Para | NO Uses Feature Flags Para |
|---|---|
| Nuevas capacidades de UI | Parches de seguridad (no deberían ser apagables) |
| Tests A/B | Parches de bugs críticos |
| Liberaciones graduales de funcionalidad | Código de migración de datos |
| Kill switches de funciones arriesgadas | Un estilo de vida de ramas eternas |
Los flags complementan, no sustituyen, a las estrategias de despliegue. Un combo habitual en producción: canary en el deploy para la seguridad de infraestructura y flag sobre la nueva función para control del lado de producto — el rollback de la función es un clic de toggle, sin redespliegue.
La higiene de flags es una disciplina propia. Dale a cada flag un dueño y una fecha de caducidad al crearlo; el flag que “quitamos el próximo sprint” sigue ahí dos años después, sin documentar y con otros tres flags anidados dentro. Un inventario de flags que crece para siempre convierte el código en una matriz combinatoria de tests que nadie puede razonar — cada flag que queda atrás es una rama que solo se ejercita en uno de sus estados.
Cómo Elegir una Estrategia
Las preguntas, en orden:
- ¿Puedes tolerar downtime? Si sí, recreate — no sobreingenierices.
- ¿Necesitas rollback instantáneo? Blue-green. Paga el 2× de infra o acepta un rollback más lento.
- ¿El cambio es arriesgado? Refactors, lógica nueva, cualquier cosa que toque rutas críticas (pagos, auth) → canary.
- ¿El comportamiento bajo carga real no está probado? Shadow antes del canary.
- En cualquier otro caso, rolling — es el default correcto para cambios stateless rutinarios.
Y por tipo de cambio, en concreto:
| Cambio | Estrategia | Duración |
|---|---|---|
| Corrección de typo | Rolling | 2 min |
| Actualización de dependencias | Rolling | 5 min |
| Nueva funcionalidad de UI | Blue-green | 10 min |
| Refactor de lógica | Canary 5→20→50→100 | 30 min |
| Cambio de esquema de BD | Expand-contract | Multi-deploy |
| Migración de infra | Shadow + canary | 1-2 horas |
Las estrategias también se componen. Los equipos maduros no eligen una — las apilan: un rolling update lleva el código, los feature flags ocultan el comportamiento nuevo, y el encendido gradual del flag actúa como canary funcional. La pregunta deja de ser “qué estrategia” y pasa a ser “qué capa carga cada tipo de riesgo” — el riesgo de infraestructura va a la estrategia de despliegue, el de producto al flag.
Estrategia de Rollback
Cada estrategia de arriba es en realidad una estrategia de rollback disfrazada de despliegue — la estrategia determina con qué rapidez deshaces, no si las cosas saldrán mal. Unas reglas que valen para todas:
- El rollback debe ser automático. Un humano haciendo SSH a las 3 AM para revertir es poco fiable por definición. Flagger y Argo Rollouts revierten al romperse una métrica;
kubectl rollout undodebe ser un comando, no un procedimiento. - Practícalo. Un rollback que nunca has ejecutado es una hipótesis. Ejecútalo cada trimestre en staging — idealmente, rompe un deploy a propósito para probar que el bucle funciona.
- No puedes des-escribir una escritura de base de datos. El código vuelve atrás; las escrituras no. Si v2 escribió filas que v1 no sabe leer, revertir el código no las recupera. Esta es la razón real de existir de expand-contract: cada estado intermedio del esquema es legible por ambas versiones.
- Mantén disponible la versión anterior. Blue-green conserva todo el entorno viejo caliente; canary mantiene a la estable sirviendo tráfico. No desmontes la versión previa hasta que la nueva sobreviva un ciclo completo de tráfico.
- Define “éxito” antes de desplegar. Escribe los criterios de aborto (tasa de error, latencia, métricas de negocio) en el pipeline — decidir qué cuenta como fallo durante un incidente garantiza elegir la respuesta equivocada.
Métricas a Vigilar Durante el Despliegue
| Métrica | Umbral Canary | Acción al Brecharse |
|---|---|---|
| Tasa de error | < 0.1% sobre baseline | Rollback del canary |
| Latencia p99 | < baseline + 20% | Rollback del canary |
| Throughput | Sin caída > 10% | Rollback del canary |
| Métrica de negocio (registros, checkouts) | Sin caída | Rollback del canary |
Los baselines importan más que los números. Si tu tasa de error ya corre al 0.05%, un umbral del 0.1% es demasiado estricto; fíjalo en relación a las últimas 24h de tráfico sano. Vigila también el denominador: un canary al 1% puede mostrar “0 errores” mientras el modo de fallo real solo se dispara con patrones que la muestra del canary no incluía — jobs nocturnos por lotes, clientes móviles, un tenant concreto.
Un detalle operativo más: los despliegues mueven métricas por motivos ajenos al código nuevo. Los reinicios de pods vacían cachés calientes (la latencia salta), los IDs de instancia nuevos confunden dashboards por instancia, y maxUnavailable baja la capacidad brevemente (el throughput se hunde). Anota los despliegues en tus dashboards o perseguirás fantasmas en cada rollout.
Lo Que Funciona
- Automatiza el rollback — un humano pulsando un botón a las 3 AM no es fiable. Ver pipelines CI/CD.
- Usa tráfico sintético — golpea el canary con tests automatizados antes que los usuarios reales.
- Despliegues pequeños — los cambios chicos se depuran más fácil y se revierten más rápido.
- Un cambio a la vez — no combines un deploy con una migración de base de datos y un cambio de configuración.
- Prueba el rollback — un rollback que nunca has practicado es una apuesta.
Errores Comunes y Solución de Problemas
- Desplegar el viernes por la tarde — pasarás el fin de semana depurando.
- Sin rollback automático — las reversiones manuales son más lentas y propensas a errores, sobre todo bajo presión.
- Combinar varios cambios en un deploy — un deploy más una migración de esquema más un cambio de config, y cuando se rompe no sabes cuál de los tres causó el problema.
- Ignorar las métricas del canary porque “los tests pasaron” — el tráfico de producción es la única prueba real.
- Olvidar la compatibilidad de base de datos en blue-green — el código viejo y el nuevo deben convivir durante el cambio.
- El despliegue se revierte una y otra vez — revisa health checks, límites de recursos y startup probes; un readiness probe que falla es la causa habitual de reinicios en cadena.
- El contenedor muere al arrancar — verifica variables de entorno, secrets y config montada; lee las primeras 50 líneas de logs antes de escalar réplicas.
Escenario: Pipeline de Despliegue para E-commerce
Un servicio de pagos en Kubernetes usando Argo Rollouts (el CRD Rollout del proyecto Argo Rollouts — distinto del Application de Argo CD):
# Argo Rollouts: despliegue canary con análisis automatizado
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payment-service
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 5 # 5% del tráfico a v2
- pause: { duration: 5m }
- setWeight: 20
- pause: { duration: 10m }
- setWeight: 50
- analysis: # análisis automático
templates:
- templateName: success-rate
args:
- name: service-name
value: payment-service
- setWeight: 100
selector:
matchLabels: { app: payment-service }
template:
spec:
containers:
- name: payment
image: registry.example.com/payment:v2.1.0
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: 500m, memory: 512Mi }
---
# AnalysisTemplate: criterios de éxito
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 1m
successCondition: result[0] >= 0.99
failureLimit: 3
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{
service="{{args.service-name}}",
status!~"5.."}[2m]))
/ sum(rate(http_requests_total{
service="{{args.service-name}}"}[2m]))
Aborto automático: tasa de error por encima del 1% durante 2 minutos, p99 por encima de 2× el baseline, o el análisis fallando 3 veces → el rollout revierte el peso de tráfico. Lecciones de correr esto en producción: el canary con análisis automático le gana al manual siempre; define los criterios de éxito antes de desplegar; expand-contract para cambios de esquema no es opcional.
Lectura Adicional
- Kubernetes: Performing a Rolling Update — mecánica de la estrategia por defecto de Deployment.
- Flagger Progressive Delivery Operator — canary automatizado con análisis de métricas para Kubernetes.
- Documentación de Argo Rollouts — referencia del CRD
RolloutyAnalysisTemplate. - Martin Fowler: BlueGreenDeployment y CanaryRelease — las definiciones de los patrones.
- Martin Fowler: ParallelChange — el patrón expand-contract para cambios de esquema.
- LaunchDarkly: Feature flag best practices — ciclo de vida y retirada de flags.
- Recursos complementarios — ejemplos ejecutables de Flagger, Argo Rollouts y blue-green con ALB de esta guía.
Preguntas frecuentes
¿Debería cada deploy usar canary?
No. Los cambios de bajo riesgo (actualizaciones de dependencias, typos) pueden usar rolling. Reserva el canary para funcionalidad de cara al usuario, refactors arriesgados y cambios que tocan rutas críticas como pagos o autenticación — la sobrecarga del análisis no es gratis.
¿Blue-green o canary — cuál es más seguro?
Canary es más seguro frente a bugs desconocidos (el radio de explosión queda limitado al porcentaje que enrutas), mientras que blue-green revierte más rápido una vez detectas el problema (segundos contra minutos). Para cambios de verdad arriesgados, shadow primero y canary después. En servicios donde domina la velocidad de rollback — pasarelas de pago, auth — gana blue-green.
¿Cuánto debe durar un canary?
Hasta tener confianza estadística. En servicios de mucho tráfico pueden bastar 15-30 minutos. En los de poco tráfico, horas o un ciclo de negocio completo. Usa error budgets y SLOs para definir "terminado".
¿Y si hay que cambiar el esquema de la base de datos?
Usa el patrón expand-contract. Paso 1: despliega el cambio de esquema (añade columna nueva, conserva la vieja). Paso 2: despliega código que escribe en ambas. Paso 3: rellena datos (backfill). Paso 4: despliega código que solo lee la nueva. Paso 5: elimina la columna vieja. Son 4-5 despliegues y te dan downtime cero.
¿Cómo manejo los despliegues multi-región?
Despliega secuencialmente, no a la vez: primero us-east, luego eu-west y después ap-southeast, con una pausa entre regiones para pillar problemas regionales. Un balanceador global (Route53, Cloudflare) gestiona los health checks, y si una región falla las demás ya están en la versión nueva.
¿Cuál es la opción sin downtime más barata?
Rolling. No necesita infraestructura extra — solo health checks y apagado ordenado. Blue-green dobla tu factura, canary añade complejidad de tooling, y shadow también la dobla. Si 30 segundos de parada son asumibles, recreate es la opción barata honesta.
Recursos Relacionados
Guia: Despliegue Blue-Green
Guía práctica sobre despliegues blue-green: arquitectura, estrategias de cambio de tráfico, migraciones de base de datos y lograr releases sin downtime con rollback instantáneo.
GuideDespliegue Canary: Rollouts Graduales y Seguros
Guía práctica de despliegues canary: división de tráfico, promoción automatizada, disparadores de rollback y releases seguros a un subconjunto de usuarios.
GuideFeature Flags: Release Progresivo y Experimentación Segura
Guía práctica de feature flags: patrones de implementación, rollouts progresivos, kill switches, A/B testing y gestión del ciclo de vida a escala.
GuideGuía de Pipelines CI/CD
Una guía práctica para construir pipelines CI/CD con GitHub Actions, testing, estrategias de deployment y procedimientos de rollback.
RecipeReceta: Despliegue Blue-Green
Despliega con zero downtime usando ambientes blue-green, conmutación instantánea de tráfico y capacidades de rollback automatizado.
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.