Tutorial: implementar Canary releases con Traefik en Docker Compose usando headers y weighted routing para despliegues graduales de aplicaciones PHP

Deploy & DevOps · Por · Publicado el · 8 min de lectura

Mapa de papel con chinchetas y hilos conectando puntos, mostrando conexiones entre ubicaciones
Representa redes y enrutamiento de tráfico entre servicios Foto: TheAndrasBarta / Pixabay

Tutorial para implementar Canary releases con Traefik en Docker Compose usando headers y weighted routing para despliegues graduales de aplicaciones PHP. Verás cómo enrutar por header/cookie para forzar la versión canary, balancear el resto por pesos y ajustar el rollout de forma segura, todo sin Kubernetes.

Qué construiremos y cuándo usar Canary

Ejecutarás dos versiones de la app PHP (stable y canary) detrás de Traefik. Las peticiones con header/cookie irán 100% a la versión canary; el resto seguirá un balanceo ponderado (weights). Esto permite validar en producción con bajo riesgo.

Usa Canary cuando necesites probar cambios reales con solo una parte del tráfico. Para intercambios instantáneos entre versiones con infraestructura idéntica, revisa el despliegue blue‑green.

Si aún estás eligiendo reverse proxy para Docker, compara en Traefik vs Nginx.

  • Dirigir tráfico por header o cookie hacia el canary
  • Balancear el resto del tráfico con pesos (ej.: 95/5)
  • Una única ruta (Host) para el consumidor

Pre‑requisitos

Necesitas un host Linux con Docker y Docker Compose instalados, acceso root para editar /etc/hosts y la puerta 80 liberada. Conocer redes Docker y labels de Traefik ayuda.

No usaremos TLS para simplificar. En producción añade HTTPS y hardening. Compara opciones en comparativa Traefik vs Caddy.

  • Docker y Docker Compose instalados
  • Puerto 80 disponible en el host
  • Editor de texto y terminal
  • Acceso sudo para editar /etc/hosts

Crear la app PHP de ejemplo (stable y canary)

Haremos una app PHP sencilla, servida por el servidor embebido de PHP, solo para demostración. No utilices el servidor embebido en producción. El código expone / y /health y diferencia versiones por variable de entorno. El comando mostrado añade una línea a /etc/hosts.

mkdir -p app

cat > app/index.php <<'PHP'
<?php
header('Content-Type: application/json');
echo json_encode([
  'version' => getenv('VERSION') ?: 'unknown',
  'hostname' => gethostname(),
  'time' => date('c'),
  'path' => $_SERVER['REQUEST_URI'] ?? '/'
]);
PHP

cat > app/health.php <<'PHP'
<?php
http_response_code(200);
echo "ok";
PHP

# Mapear domínio local para testes (requer sudo)
echo '127.0.0.1 app.local' | sudo tee -a /etc/hosts

Definir docker-compose.yml con Traefik, headers y weights

Crearemos Traefik como reverse proxy, dos servicios de la app (stable y canary) y las reglas: un router de alta prioridad para header/cookie y un router por defecto con weighted routing.

Este arreglo implementa, en la práctica, el tutorial: implementar Canary releases con Traefik en Docker Compose usando headers y weight routing para despliegues graduales de aplicaciones PHP.

version: '3.9'

services:
  traefik:
    image: traefik:v2.10
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --accesslog=true
      - --log.level=INFO
    ports:
      - '80:80'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - web
    labels:
      - traefik.enable=true

      # Router canary por header/cookie (prioridade alta)
      - traefik.http.routers.app-canary.rule=Host(`app.local`) && (Headers(`X-Canary`,`1`) || Cookie(`canary`,`1`))
      - traefik.http.routers.app-canary.entrypoints=web
      - traefik.http.routers.app-canary.priority=1000
      - traefik.http.routers.app-canary.service=app-canary@docker

      # Router padrão (Host) usando weighted routing
      - traefik.http.routers.app.rule=Host(`app.local`)
      - traefik.http.routers.app.entrypoints=web
      - traefik.http.routers.app.service=app-weighted

      # Services ponderados: comece 100% stable, 0% canary
      - traefik.http.services.app-weighted.weighted.services.stable.name=app-stable@docker
      - traefik.http.services.app-weighted.weighted.services.stable.weight=100
      - traefik.http.services.app-weighted.weighted.services.canary.name=app-canary@docker
      - traefik.http.services.app-weighted.weighted.services.canary.weight=0

  app-stable:
    image: php:8.2-cli-alpine
    working_dir: /app
    command: sh -c 'php -S 0.0.0.0:8000 -t /app'
    environment:
      - VERSION=stable
    volumes:
      - ./app:/app:ro
    networks:
      - web
    labels:
      - traefik.enable=true
      - traefik.http.services.app-stable.loadbalancer.server.port=8000
      - traefik.http.services.app-stable.loadbalancer.healthcheck.path=/health
      - traefik.http.services.app-stable.loadbalancer.healthcheck.interval=5s

  app-canary:
    image: php:8.2-cli-alpine
    working_dir: /app
    command: sh -c 'php -S 0.0.0.0:8000 -t /app'
    environment:
      - VERSION=canary
    volumes:
      - ./app:/app:ro
    networks:
      - web
    labels:
      - traefik.enable=true
      - traefik.http.services.app-canary.loadbalancer.server.port=8000
      - traefik.http.services.app-canary.loadbalancer.healthcheck.path=/health
      - traefik.http.services.app-canary.loadbalancer.healthcheck.interval=5s

networks:
  web: {}

Subir el entorno y validar rutas por header/cookie

Levanta los contenedores y realiza peticiones de prueba. Primero valida la ruta por defecto (Host). Después fuerza el tráfico hacia canary con header y con cookie. Si usas firewall local, abre la puerta 80.

docker compose up -d

# Rota padrão (deve ir para stable)
curl -s http://app.local/

# Forçar canary pelo header X-Canary=1
curl -s -H 'X-Canary: 1' http://app.local/

# Forçar canary por cookie canary=1
curl -s --cookie 'canary=1' http://app.local/

# Conferir health dos serviços
curl -s -I http://app.local/health

Rollout gradual: ajustar weights y aplicar

Edita docker-compose.yml y ajusta los pesos. Una secuencia común: 99/1, 95/5, 90/10, 75/25 y 50/50, monitorizando métricas y errores entre pasos. Siempre garantiza compatibilidad de base de datos y esquema.

  • Aumenta el weight del canary de forma gradual
  • Monitorea errores, latencia y saturación
  • Reduce a cero en caso de fallos (rollback)
# Exemplo: mudar para 90% stable, 10% canary
# No serviço traefik, ajuste as labels:
# - traefik.http.services.app-weighted.weighted.services.stable.weight=90
# - traefik.http.services.app-weighted.weighted.services.canary.weight=10

# Aplique sem recriar os apps
docker compose up -d --no-deps traefik

# Gere amostras e observe distribuição
for i in $(seq 1 20); do curl -s http://app.local/ | grep -o '"version":"[a-z]*"'; done | sort | uniq -c

Sesiones, healthchecks y observabilidad

Sesiones de usuario: el balanceo ponderado puede alternar entre stable y canary. Si tu app necesita afinidad, usa enrutamiento por cookie para usuarios específicos o guarda sesiones externamente (por ejemplo en Redis).

Los healthchecks HTTP están configurados en /health. Solo los contenedores saludables reciben tráfico. Para seguimiento, revisa los logs de acceso de Traefik y las métricas de la aplicación.

Centraliza logs estructurados para depurar más rápido. Consulta logs JSON y correlación y, para dashboards, mira Prometheus y Grafana con Docker Compose.

  • Afinidad por cookie para grupos piloto
  • Healthchecks excluyen instancias enfermas
  • Logs y métricas para feedback rápido
# Acompanhar acessos direcionados pelo Traefik
docker logs -f traefik | grep app.local

Confirmaciones finales, próximos pasos y errores comunes

Confirma que: 1) las peticiones con header/cookie siempre van a la versión canary; 2) la ruta por defecto respeta los weights; 3) el rollback deja a 0 el weight del canary. Automatiza el cambio de pesos en tu pipeline de CI, validando métricas entre etapas.

Para funcionalidades riesgosas combina Canary con feature flags en el código. Mira ideas en feature flags en monolitos PHP.

¿El host no resuelve? Verifica que app.local esté en /etc/hosts. ¿Puerto 80 ocupado? Para el servicio que lo usa. ¿Sin efecto los weights? Confirma que las labels estén en el servicio traefik y vuelve a ejecutar el up. ¿Header/cookie ignorados? Ajusta la prioridad del router canary.

Sesiones perdidas entre versiones: usa cookie para dirigir siempre a canary durante la prueba, o almacena sesiones externamente. ¿Errores 5xx en aumento? Haz rollback inmediato (weight=0) e investiga logs y healthchecks.

  • /etc/hosts y puertos correctos
  • Labels deben estar en el servicio traefik, no en las apps
  • Prioridad alta en el router canary (priority)
  • Rollback rápido si aparecen errores 5xx

Preguntas frecuentes

¿Puedo hacer Canary sin Kubernetes?

Sí. Traefik con Docker Compose ofrece ruteo por headers/cookies y weighted routing. Es suficiente para muchos escenarios: controlas el flujo entre stable y canary mediante labels y red Docker, sin la complejidad de Kubernetes.

¿Cómo rutar por cookie o header en Traefik?

Crea un router con prioridad alta y una regla que combine Host con Headers o Cookie. Envía ese router al servicio canary. El resto del tráfico cae en el router por defecto, que usa weighted routing para distribuir entre stable y canary.

¿Qué pasa con las sesiones de usuario durante el canary?

Como el tráfico puede alternar entre versiones, las sesiones locales pueden perderse. Usa cookie para forzar canary a usuarios seleccionados, o guarda sesiones en un backend compartido (por ejemplo Redis) para permitir alternancia sin pérdida de estado.

¿Cómo automatizar el rollout gradual?

En el pipeline de CI modifica los valores de weight en las labels de Traefik y redeploya solo el servicio traefik. Entre cada incremento valida métricas y errores. Si algo va mal, reduce el weight del canary a cero.

¿Cómo manejar cambios en la base de datos?

Mantén compatibilidad entre versiones. Primero evoluciona el esquema de forma compatible (expansión), luego actualiza el código; solo después elimina campos antiguos (contracción). Para cambios arriesgados, combina con feature flags en la app.

¿Quieres adaptar Canary a tu entorno?

Si tu escenario involucra múltiples servicios, TLS, sesiones y validaciones automáticas, podemos diseñar un rollout canario con observabilidad y rollback seguro.

Hablar sobre Canary con Traefik

Ver también