DevOps

Despliegue zero-downtime en Kubernetes: rolling updates, canary y blue-green en la práctica

Ruslan Ismailov Publicado 14 min de lectura
D

Introducción: qué es el despliegue zero-downtime y por qué es crítico

Cada vez que publicas una nueva versión de tu aplicación, surge un riesgo: los usuarios pueden encontrar errores, indisponibilidad del servicio o comportamientos impredecibles. El despliegue zero-downtime es un conjunto de prácticas y enfoques técnicos que permiten actualizar el entorno de producción sin interrumpir el procesamiento de solicitudes.

En el contexto de Kubernetes, el despliegue zero-downtime ha dejado de ser una rareza: es un requisito básico para cualquier producto serio. La plataforma ofrece mecanismos integrados (rolling updates) y también permite implementar estrategias más avanzadas: blue-green y canary. En este artículo analizaremos cada una de ellas con manifiestos y comandos reales.

El público objetivo de este artículo son ingenieros DevOps, SRE y desarrolladores backend que ya trabajan con Kubernetes y desean construir pipelines de entrega confiables.

Rolling Update en Kubernetes: configuración y puntos conflictivos

El rolling update es la estrategia de despliegue predeterminada en Kubernetes. Los nuevos pods se inician gradualmente mientras los antiguos se terminan a medida que los nuevos están listos. Esto permite mantener la disponibilidad del servicio durante toda la actualización.

Parámetros clave: maxSurge y maxUnavailable

El comportamiento del rolling update se controla mediante dos parámetros en la sección strategy del manifiesto Deployment:

  • maxSurge — número máximo de pods por encima del número deseado de réplicas que pueden existir simultáneamente. Se puede expresar como número o porcentaje.
  • maxUnavailable — número máximo de pods que pueden estar no disponibles durante el proceso de actualización.

Ejemplo de manifiesto Deployment con rolling update configurado:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  replicas: 4
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: my-app
        version: v2
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v2
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 20

Readiness y Liveness probes — un elemento obligatorio

Sin probes correctamente configuradas, el rolling update pierde su sentido. El readiness probe indica a Kubernetes que el pod está listo para recibir tráfico. Mientras la probe no sea satisfactoria, el pod no se incluye en el balanceo. El liveness probe determina si el proceso sigue vivo; si no es así, el pod se reinicia.

Un error típico: la aplicación arranca, pero aún no ha terminado su inicialización (calentamiento de cachés, migraciones). Sin readiness probe, Kubernetes comenzará a enviar tráfico a una instancia no lista. Utiliza también startupProbe para aplicaciones con arranques prolongados.

Comandos kubectl para gestionar el rolling update

# Actualizar la imagen
kubectl set image deployment/my-app my-app=my-registry/my-app:v2 -n production

# Seguir el proceso
kubectl rollout status deployment/my-app -n production

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

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

Despliegue Blue-Green: cambio de tráfico mediante Service e Ingress

El despliegue blue-green implica tener dos entornos idénticos: blue (versión actual en producción) y green (nueva versión). El tráfico en todo momento se dirige únicamente a uno de ellos. Tras realizar pruebas exitosas del entorno green, el tráfico se redirige con un solo comando.

Manifiesto del despliegue blue y green

# Blue Deployment (producción actual)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-blue
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      slot: blue
  template:
    metadata:
      labels:
        app: my-app
        slot: blue
        version: v1
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v1
          ports:
            - containerPort: 8080
---
# Green Deployment (nueva versión)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-green
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      slot: green
  template:
    metadata:
      labels:
        app: my-app
        slot: green
        version: v2
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v2
          ports:
            - containerPort: 8080

Service y cambio de tráfico

apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
  namespace: production
spec:
  selector:
    app: my-app
    slot: blue   # Cambiar a "green" para redirigir el tráfico
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

El cambio de tráfico se realiza aplicando un patch al servicio:

kubectl patch service my-app-svc -n production \
  -p '{"spec":{"selector":{"slot":"green"}}}'

Al usar Ingress con NGINX Ingress Controller o similares, es posible cambiar el tráfico a nivel del recurso Ingress modificando el servicio backend. Esto proporciona un control adicional sin necesidad de modificar el Service en sí.

Ventaja del blue-green: cambio instantáneo y reversión igualmente instantánea. Desventaja: recursos duplicados durante el período de despliegue.

Despliegue Canary: rollout gradual con reglas de peso

El despliegue canary permite dirigir un pequeño porcentaje del tráfico hacia la nueva versión de la aplicación sin exponer a todos los usuarios al riesgo. Es la estrategia ideal para probar cambios bajo carga real.

Canary con Kubernetes nativo (sin service mesh)

La forma más sencilla es lanzar un canary-deployment con pocas réplicas junto al stable-deployment. Kubernetes balancea el tráfico entre los pods de forma proporcional a su cantidad.

# Stable Deployment: 9 réplicas = ~90% del tráfico
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-stable
  namespace: production
spec:
  replicas: 9
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        track: stable
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v1
---
# Canary Deployment: 1 réplica = ~10% del tráfico
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-canary
  namespace: production
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        track: canary
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v2

El Service selecciona pods únicamente por la etiqueta app: my-app, abarcando ambos despliegues.

Canary mediante Ingress con anotaciones de peso (NGINX)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-canary-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
    - host: my-app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app-canary-svc
                port:
                  number: 80

La anotación canary-weight: "10" dirige el 10% del tráfico al canary. El valor se incrementa gradualmente — 10%, 25%, 50%, 100% — a medida que crece la confianza en la estabilidad de la nueva versión.

Canary con Argo Rollouts

Para una gestión avanzada del despliegue canary, se recomienda usar Argo Rollouts — una extensión de Kubernetes que añade el tipo de recurso Rollout con soporte nativo para canary, blue-green y análisis de métricas.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
  namespace: production
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: {duration: 5m}
        - setWeight: 30
        - pause: {duration: 10m}
        - setWeight: 60
        - pause: {duration: 10m}
        - setWeight: 100
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:v2
          ports:
            - containerPort: 8080

Integración de las estrategias de despliegue en el pipeline CI/CD

Las estrategias de despliegue sin interrupciones alcanzan todo su potencial únicamente combinadas con un pipeline CI/CD automatizado. Veamos un flujo típico con GitLab CI como ejemplo:

stages:
  - build
  - test
  - deploy-canary
  - promote
  - rollback

build:
  stage: build
  script:
    - docker build -t my-registry/my-app:$CI_COMMIT_SHA .
    - docker push my-registry/my-app:$CI_COMMIT_SHA

deploy-canary:
  stage: deploy-canary
  script:
    - kubectl set image deployment/my-app-canary
        my-app=my-registry/my-app:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/my-app-canary -n production
  environment:
    name: production/canary

promote:
  stage: promote
  when: manual
  script:
    - kubectl set image deployment/my-app-stable
        my-app=my-registry/my-app:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/my-app-stable -n production

rollback:
  stage: rollback
  when: manual
  script:
    - kubectl rollout undo deployment/my-app-stable -n production
    - kubectl rollout undo deployment/my-app-canary -n production

Principios clave de integración:

  • La etiqueta de la imagen Docker se vincula al commit ($CI_COMMIT_SHA), lo que garantiza la reproducibilidad.
  • Cada paso del despliegue se verifica mediante kubectl rollout status.
  • El promote (rollout completo) se ejecuta manualmente tras observar las métricas del canary.
  • El rollback está disponible como paso independiente del pipeline.

Rollback: automático y manual

Incluso el despliegue más cuidadoso puede salir mal. Kubernetes almacena el historial de revisiones del Deployment, lo que permite revertir rápidamente los cambios.

Rollback manual

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

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

# Ver revisiones con detalles
kubectl rollout history deployment/my-app -n production --revision=2

Rollback automático con Argo Rollouts y análisis de métricas

Argo Rollouts admite AnalysisTemplate — una descripción de las condiciones de éxito del despliegue basada en métricas de Prometheus:

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
  namespace: production
spec:
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result[0] >= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            sum(rate(http_requests_total{status!~"5..",app="my-app"}[1m]))
            /
            sum(rate(http_requests_total{app="my-app"}[1m]))

Si la tasa de éxito cae por debajo del 95% tres veces consecutivas, Argo Rollouts interrumpe automáticamente el despliegue y revierte a la versión anterior.

También es recomendable configurar progressDeadlineSeconds en el Deployment — si el despliegue no finaliza en el tiempo indicado, Kubernetes lo marca como fallido:

spec:
  progressDeadlineSeconds: 300

Monitoreo del despliegue: cómo verificar que la actualización fue exitosa

El despliegue zero-downtime es imposible sin observabilidad. Qué debes monitorear:

  • Error rate — porcentaje de respuestas 5xx. Un aumento repentino indica un problema.
  • Latency (p50, p95, p99) — la degradación de la latencia puede ser señal de una regresión.
  • Pod restart count — reinicios frecuentes indican crashes en la aplicación.
  • Readiness probe failures — pods que no superan la verificación de disponibilidad.
  • Kubernetes eventskubectl get events -n production --sort-by=.lastTimestamp.

Comandos útiles para monitorear el despliegue en tiempo real

# Estado del despliegue
kubectl rollout status deployment/my-app -n production

# Estado de los pods
kubectl get pods -n production -l app=my-app -w

# Descripción del pod ante problemas
kubectl describe pod <pod-name> -n production

# Logs en tiempo real
kubectl logs -f -l app=my-app -n production --tail=100

# Eventos del namespace
kubectl get events -n production --sort-by=.lastTimestamp

Integra Prometheus + Grafana con dashboards de despliegue. Una buena práctica es anotar automáticamente el dashboard de Grafana en cada despliegue, lo que permite correlacionar visualmente los cambios en las métricas con el momento exacto de la actualización.

Comparación de estrategias de despliegue

Cada estrategia es adecuada para escenarios específicos. A continuación, las características clave:

  • Rolling Update: integrado en Kubernetes, mínima sobrecarga de recursos, adecuado para la mayoría de los servicios. Desventaja: durante la actualización coexisten dos versiones simultáneamente, lo que requiere compatibilidad hacia atrás en la API y el esquema de base de datos.
  • Blue-Green: cambio y reversión instantáneos, ideal para sistemas críticos. Requiere el doble de recursos durante el despliegue. Más complejo con componentes stateful.
  • Canary: la estrategia más segura — el tráfico real prueba la nueva versión en una pequeña fracción de usuarios. Requiere un monitoreo de calidad y herramientas de gestión de pesos (Argo Rollouts, Istio, NGINX). Adecuado para sistemas de alta carga con gran volumen de tráfico.

Recomendaciones para elegir:

  1. Comienza con Rolling Update — es la opción predeterminada razonable para la mayoría de las aplicaciones.
  2. Pasa a Blue-Green si necesitas una reversión instantánea garantizada y dispones de recursos suficientes.
  3. Implementa Canary para servicios de alta carga donde incluso un 1% de errores es crítico y dispones de un sistema de monitoreo maduro.

Conclusión

El despliegue zero-downtime en Kubernetes no es solo una configuración técnica, sino una cultura de ingeniería. El rolling update es el punto de partida adecuado para la mayoría de los equipos. Blue-green aporta confianza en actualizaciones críticas. Canary es la estrategia más madura para sistemas en producción con alta carga.

Cualquiera de estas estrategias funciona de forma confiable únicamente en combinación con readiness/liveness probes correctamente configuradas, un pipeline CI/CD automatizado y un monitoreo completo. Invierte tiempo en configurar estos componentes — te lo agradecerás con noches tranquilas y releases seguros.

El mejor despliegue es aquel que los usuarios no notan.

Tecnologías

Etiquetas

Ruslan Ismailov

Desarrollador Senior Web / Backend. Desarrollador senior web/backend con 9 años de experiencia. Stack: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, microservicios, CI/CD. Más sobre mí →