Módulo 5: Gitops With Argocd
7. Estrategias de despliegue: rolling, blue/green y canary
Descripción
cicd-and-gitops-on-aws-guide M7.5 te nombró, con sintaxis verificada pero sin ejecutar nada, las tres estrategias estándar para pasar tráfico real de usuarios entre dos versiones de una aplicación — y cerró esa lección con una frase textual que apunta directo a este módulo: "kubernetes-and-eks-in-production-guide — donde estas tres estrategias se implementan de verdad, con un clúster real (...), probablemente junto con ArgoCD/Flux (...), formando el panorama completo de GitOps pull-based + despliegue de aplicación que esta guía solo nombra." Esta lección recibe esa delegación textual. andes-cargo-status-api ya usa RollingUpdate desde el Módulo 2 —vas a confirmarlo con evidencia real de tu propio clúster—; blue/green y canary, en cambio, necesitan una pieza que este laboratorio nombra pero no instala.
Conexión con el módulo
Esta es la última lección conceptual del módulo antes del proyecto final. La lección 8 usa exactamente el mecanismo de escalado que esta lección distingue con precisión de un RollingUpdate de verdad — una distinción que vale la pena tener clara antes de llegar ahí.
RollingUpdate: ya configurado, confirmado con evidencia real
deployment.yaml declara esta estrategia desde el Módulo 2, sin que ninguna lección posterior la haya tocado:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
Confírmalo tú mismo, contra el Deployment real que ArgoCD administra desde la lección 6:
kubectl get deployment andes-cargo-status-api -n andes-cargo -o jsonpath='{.spec.strategy}' | python3 -m json.tool
Qué esperar (literal, ejecutado):
{
"rollingUpdate": {
"maxSurge": 1,
"maxUnavailable": 0
},
"type": "RollingUpdate"
}
maxSurge: 1 — Kubernetes puede crear una réplica extra, por encima de la cantidad deseada, mientras dura la transición. maxUnavailable: 0 — Kubernetes nunca puede tener ninguna réplica fuera de servicio durante la transición; siempre tiene que haber, como mínimo, la cantidad completa de réplicas deseadas respondiendo. Esta combinación es una decisión explícita, más estricta que el ejemplo genérico que mostró cicd-and-gitops-on-aws-guide (maxUnavailable: 1): para un servicio que los socios logísticos de Andes Cargo consultan todo el día, cero indisponibilidad durante un despliegue es la prioridad, a costa de un Pod extra corriendo brevemente durante la transición.
El detalle que importa: RollingUpdate gobierna reemplazos de versión, no cambios de conteo
Aquí está la precisión técnica que esta lección necesita antes de que llegues al proyecto final. maxSurge y maxUnavailable solo entran en juego cuando el Pod template del Deployment cambia —por ejemplo, un tag de imagen nuevo, una variable de entorno nueva, un límite de recursos distinto—. Un cambio que solo modifica spec.replicas (subir o bajar la cantidad de réplicas deseadas, sin tocar nada del Pod template) es un evento de escalado, gestionado directamente por el ReplicaSet existente — no dispara ninguna lógica de RollingUpdate, porque no hay ninguna "versión nueva" que introducir gradualmente.
Confírmalo con el historial real de este Deployment:
kubectl rollout history deployment/andes-cargo-status-api -n andes-cargo
kubectl get replicaset -n andes-cargo
Qué esperar (literal, ejecutado, en este punto del módulo):
deployment.apps/andes-cargo-status-api
REVISION CHANGE-CAUSE
1 <none>
NAME DESIRED CURRENT READY AGE
andes-cargo-status-api-548966dd97 2 2 2 94m
Una sola REVISION, un solo ReplicaSet (548966dd97), a pesar de todos los cambios de réplicas que este módulo ya hizo. Eso es exactamente la confirmación de la distinción: cada vez que cambió spec.replicas —en la lección 5 (selfHeal, réplicas 5→2→5), en el proyecto de la lección 8 (réplicas 3→5)—, Kubernetes ajustó el tamaño del mismo ReplicaSet, sin crear ninguno nuevo. Un RollingUpdate de verdad —el que reemplaza gradualmente réplicas viejas por nuevas, respetando maxSurge/maxUnavailable— solo ocurriría si algo cambiara dentro de spec.template (la definición del propio Pod): eso crearía un ReplicaSet nuevo, con un hash distinto, y REVISION subiría a 2.
ESCALADO (lo que este módulo ejecuta) ROLLING UPDATE (lo que dispararía
un cambio de imagen o de template)
ReplicaSet 548966dd97 ReplicaSet 548966dd97 (viejo)
replicas: 3 ──────▶ replicas: 5 3 réplicas ──▶ 2 réplicas ──▶ 0
(mismo hash, │ │
mismo ReplicaSet, ▼ ▼
sin nuevo REVISION) ReplicaSet a1b2c3d4e (nuevo)
0 réplicas ──▶ 1 ──▶ 3
(hash nuevo, REVISION 2,
maxSurge/maxUnavailable
SÍ gobiernan esta transición)
Esto no le resta valor al proyecto de la lección 8 —"un cambio en Git, reflejado solo, sin kubectl apply" sigue siendo la prueba central de todo el módulo—, pero vale la pena que sepas, con precisión, qué mecanismo exacto estás viendo: convergencia de GitOps sobre un escalado, no un RollingUpdate de versión. deployment.yaml sigue declarando la estrategia RollingUpdate para el día en que sí cambie algo del Pod template —una actualización de imagen, por ejemplo—, y esa transición sí respetaría maxSurge: 1/maxUnavailable: 0 tal como los declaraste desde el Módulo 2.
Blue/green: dos entornos completos, cambio instantáneo
Según documentación de AWS, ya citada en cicd-and-gitops-on-aws-guide M7.5: "the blue/green deployment strategy is a type of immutable deployment which also requires creation of another environment. Once the new environment is up and passed all tests, traffic is shifted to this new deployment." La diferencia contra RollingUpdate: en ningún momento hay una mezcla parcial de tráfico entre versiones —es la versión vieja o la nueva, nunca las dos sirviendo simultáneamente—, y volver atrás es tan simple como redirigir el tráfico de nuevo al entorno viejo, que nunca se destruyó.
Kubernetes puro (el Deployment nativo que ya conoces) no incluye blue/green — no hay ningún strategy: type: BlueGreen en su documentación oficial. Implementarlo de verdad exige una pieza adicional que administre dos Deployment completos y decida a cuál apunta el Service en cada momento — típicamente Argo Rollouts, del mismo proyecto CNCF que ArgoCD, con su propio recurso Rollout que reemplaza a Deployment:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: andes-cargo-status-api
spec:
strategy:
blueGreen:
activeService: status-api-service
previewService: status-api-service-preview
activeService es el Service que recibe tráfico real hoy; previewService apunta al entorno nuevo, todavía sin tráfico de producción, disponible para pruebas antes de decidir el corte. Nada de este YAML corrió contra andes-cargo-cluster — Argo Rollouts (versión estable más reciente, v1.9.1, verificada contra su repositorio oficial) no está instalado en este laboratorio; se nombra, con sintaxis verificada, no se instala.
Canary: una porción pequeña, primero
El nombre viene de la práctica minera real: un canario, más sensible a gases tóxicos que un humano, alertaba temprano. Un despliegue canary aplica la misma lógica al tráfico de una aplicación: la versión nueva recibe primero una porción pequeña (5%, 1%) del tráfico real, mientras la mayoría sigue en la versión estable; si las métricas de esa porción se mantienen sanas, el porcentaje sube gradualmente.
Igual que blue/green, Kubernetes puro no lo incluye nativamente — Argo Rollouts, según su propia documentación, "provide[s] advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes":
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: andes-cargo-status-api
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 10m }
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 100
setWeight: 5 manda el 5% del tráfico real a la versión nueva; pause: { duration: 10m } detiene el avance automático diez minutos —tiempo para que un sistema de monitoreo (fuera del alcance de esta guía, territorio de sre-and-incident-response-guide) confirme que las métricas siguen sanas antes de seguir subiendo el porcentaje—. Tampoco corrió contra este clúster.
Las tres, por contraste directo
| Rolling (ejecutado, M2-M8) | Blue/green (nombrado) | Canary (nombrado) | |
|---|---|---|---|
| ¿Cuántos entornos completos? | Uno, en transición gradual | Dos, completos, en paralelo | Uno, con una porción de tráfico separada |
| ¿Mezcla de tráfico entre versiones? | Sí, sin control fino | No — cambio instantáneo | Sí, con control fino (setWeight) |
| Velocidad de rollback | Media | Instantánea | Rápida (setWeight a 0) |
Soporte nativo en Deployment | Sí (strategy.type) | No — requiere Argo Rollouts | No — requiere Argo Rollouts |
| ¿Corrió en este laboratorio? | Sí — deployment.yaml desde el Módulo 2 | No — YAML mostrado, verificado, sin instalar | No — YAML mostrado, verificado, sin instalar |
Por qué este laboratorio no instala Argo Rollouts
La misma disciplina de honestidad de todo este ecosistema: instalar una herramienta adicional solo para nombrar dos estrategias sin un escenario real de negocio que las necesite —Andes Cargo nunca tuvo, en este ecosistema, dos versiones de andes-cargo-status-api compitiendo por tráfico real al mismo tiempo— sería agregar peso sin agregar aprendizaje verificable. RollingUpdate resuelve, de sobra, el único escenario que este caso de uso tiene: reemplazar una versión por otra, sin downtime, para un servicio de solo lectura. Argo Rollouts queda nombrado, con su versión real (v1.9.1) y su sintaxis verificada contra documentación oficial, para cuando un lector necesite blue/green o canary en un caso de uso que sí lo justifique.
Errores comunes
Pensar que el proyecto de la lección 8 va a "mostrar un RollingUpdate" en el sentido de reemplazo de versión (el error que esta misma lección previene). Qué pasa: alguien llega a la lección 8 esperando ver dos ReplicaSet distintos, uno reemplazando al otro gradualmente. Cómo detectarlo: si after de la lección 8 buscas un REVISION 2 en kubectl rollout history y no lo encuentras. Cómo corregirlo: la lección 8 cambia replicas, no el Pod template — es un evento de escalado sobre el mismo ReplicaSet, como esta lección ya demostró con evidencia real. La prueba de la lección 8 es sobre GitOps (convergencia sin kubectl apply), no sobre RollingUpdate como mecanismo de reemplazo de versión.
Creer que strategy: type: BlueGreen es un valor válido dentro de un Deployment nativo (de expectativa técnica, ya advertido por cicd-and-gitops-on-aws-guide M7.5, reforzado aquí con el recurso Rollout real). Qué pasa: alguien busca cambiar deployment.yaml para usar blue/green sin instalar nada adicional. Cómo detectarlo: si buscas ese valor en la documentación oficial de Deployment y no lo encuentras. Cómo corregirlo: Deployment.spec.strategy.type solo acepta RollingUpdate o Recreate (reemplazo total, sin ninguna transición gradual, fuera del alcance de esta guía porque implica downtime). Blue/green y canary exigen reemplazar Deployment por completo con el recurso Rollout de Argo Rollouts, un controlador adicional.
Confundir esta lección con el rollback del Módulo 6 de cicd-and-gitops-on-aws-guide (de capas, el mismo error que ya advirtió esa guía). Qué pasa: alguien piensa que blue/green es "una forma más avanzada de git revert". Cómo detectarlo: si crees que podrías reemplazar un git revert de andes-cargo-k8s con "usar blue/green". Cómo corregirlo: son problemas de capas distintas — el rollback de Git revierte un commit declarativo (no hay dos versiones de infraestructura corriendo en paralelo en ningún momento); blue/green resuelve cómo pasar tráfico real entre dos versiones de una aplicación corriendo simultáneamente, un problema que solo existe cuando hay réplicas activas sirviendo usuarios.
Ejercicios
Ejercicio 1 — Distingue escalado de RollingUpdate, sin ayuda. Sin volver a leer esta lección, explica en dos frases la diferencia entre "cambiar spec.replicas de 3 a 5" y "cambiar la imagen de un Deployment" — ¿cuál de las dos dispara la lógica de maxSurge/maxUnavailable, y por qué?
Ver solución
Cambiar spec.replicas es un evento de escalado: el ReplicaSet existente simplemente crece o se reduce, sin crear ningún ReplicaSet nuevo, y maxSurge/maxUnavailable no entran en juego porque no hay ninguna "versión nueva" que introducir gradualmente. Cambiar la imagen (o cualquier otro campo de spec.template) sí dispara RollingUpdate de verdad: Kubernetes crea un ReplicaSet nuevo con un hash distinto, y reemplaza réplicas del viejo por réplicas del nuevo, respetando maxSurge/maxUnavailable en cada paso de la transición.
Ejercicio 2 — Elige la estrategia correcta para un escenario nuevo. Andes Cargo quiere probar una versión experimental de andes-cargo-status-api con un algoritmo de caché distinto, midiendo el impacto en latencia con una porción pequeña de tráfico real antes de decidir si la adopta por completo. ¿Qué estrategia de esta lección encaja, y por qué ninguna de las otras dos?
Ver solución
Canary — el objetivo explícito es medir el impacto en una porción pequeña antes de decidir, exactamente lo que setWeight con pasos incrementales está diseñado para hacer. RollingUpdate no sirve para esto porque no da control fino sobre qué porcentaje de tráfico ve la versión nueva en un momento dado —simplemente reemplaza réplicas sin distinguir cuál Pod recibe qué solicitud—. Blue/green tampoco encaja bien: es un cambio instantáneo de 0% a 100%, sin ningún paso intermedio donde solo una porción pequeña vea la versión nueva.
Ejercicio 3 — Explica por qué este laboratorio no instala Argo Rollouts, con tus propias palabras. En dos o tres frases, justifica la decisión de esta lección de nombrar Argo Rollouts sin instalarlo, usando el criterio de honestidad de todo este ecosistema.
Ver solución
Una explicación razonable: "Instalar una herramienta adicional solo para mostrar sintaxis, sin un escenario real de negocio que la necesite, sería agregar peso al laboratorio sin agregar ningún aprendizaje verificable con evidencia real — el mismo criterio que ya usó esta guía para no instalar cert-manager/external-dns en el Módulo 4. andes-cargo-status-api nunca tuvo, en este caso de uso, dos versiones compitiendo por tráfico real al mismo tiempo, así que RollingUpdate ya resuelve completamente el problema que este caso concreto tiene."
Resumen y siguiente paso
Esta lección recibió la delegación textual de cicd-and-gitops-on-aws-guide M7.5 y confirmó, con evidencia real de tu propio clúster, que RollingUpdate está configurado desde el Módulo 2 (maxSurge: 1, maxUnavailable: 0) — y estableció una distinción técnica precisa que el proyecto siguiente necesita: un cambio de replicas es un evento de escalado sobre el mismo ReplicaSet, no un RollingUpdate de reemplazo de versión, que solo se dispara cuando cambia el Pod template. Blue/green y canary quedaron nombrados, con sintaxis verificada y su versión real (Argo Rollouts v1.9.1), sin instalarse — un controlador adicional que este caso de uso, hasta hoy, nunca necesitó.
Antes de avanzar deberías poder: explicar la diferencia entre escalado y RollingUpdate con el kubectl rollout history de esta lección como evidencia; nombrar el recurso que Argo Rollouts usa en vez de Deployment; y elegir la estrategia correcta para un escenario de negocio dado.
Siguiente lección: el proyecto final del módulo. Ahí subes replicas: 3 → 5 con git push, sin ningún kubectl apply — la prueba central de todo este módulo, ahora con la precisión técnica de esta lección ya instalada: lo que vas a ver es GitOps convergiendo un escalado, no un RollingUpdate de versión.
Recursos
- Kubernetes — Deployments, Rolling Update strategy — documentación oficial de
RollingUpdate,maxSurgeymaxUnavailable, confirmada contra eldeployment.yamlreal de esta lección. - Argo Rollouts — Documentation — documentación oficial de la herramienta que extiende Kubernetes con blue/green y canary, fuente del YAML de
Rolloutde esta lección. - Argo Rollouts — Releases — confirmación de la versión estable más reciente (
v1.9.1) citada en esta lección. - AWS Whitepaper — Practicing CI/CD on AWS, Deployment methods — fuente de la definición de blue/green, ya citada en
cicd-and-gitops-on-aws-guideM7.5. cicd-and-gitops-on-aws-guide(NIEVA), Módulo 7, lección 5 — la fuente textual completa de la delegación que esta lección recibe.