Testing en producción: canary deployments, feature flags y chaos engineering
Staging miente
Staging es un entorno que se parece a producción pero no es producción. Los datos son diferentes (menos volumen, menos variedad, menos usuarios concurrentes). Las integraciones de terceros están en modo sandbox. El tráfico es sintético. Y por tanto, los problemas que staging detecta son un subconjunto de los que producción revelará.
No es un argumento contra staging. Staging es necesario. Es un argumento a favor de complementar staging con testing en producción: técnicas diseñadas para validar código con tráfico real, usuarios reales, y la complejidad real del sistema en funcionamiento.
Testing en producción no significa “desplegar y rezar”. Significa desplegar de forma controlada, observar métricas en tiempo real, y tener la capacidad de revertir en segundos si algo va mal. Es ingeniería, no temeridad.
Canary deployments: el termómetro antes de la inmersión
Un canary deployment despliega la nueva versión a un subconjunto pequeño de usuarios (típicamente 1-5%) mientras el resto sigue con la versión anterior. Si las métricas del canary son buenas, se incrementa progresivamente. Si son malas, se revierte.
Implementación práctica
En Kubernetes: la forma más común es con dos Deployments (estable y canary) y un Ingress que distribuye tráfico por peso. Istio y Linkerd soportan traffic splitting nativo. Argo Rollouts automatiza el proceso completo: despliega el canary, monitoriza métricas, avanza o revierte automáticamente.
# Argo Rollouts - canary strategy
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: {duration: 10m}
- setWeight: 20
- pause: {duration: 10m}
- setWeight: 50
- pause: {duration: 10m}
- setWeight: 100
analysis:
templates:
- templateName: error-rate
args:
- name: service-name
value: api-server
En serverless (AWS Lambda): Lambda aliases con traffic shifting. Configuras una alias que distribuye tráfico entre dos versiones. CodeDeploy automatiza el progreso del canary basándose en alarmas de CloudWatch.
En servidores tradicionales: un load balancer que redirige un porcentaje del tráfico al servidor con la nueva versión. Nginx con split_clients, HAProxy con weight, o el balanceador de tu cloud (ALB weighted target groups).
Las métricas que determinan el éxito del canary
El canary pasa si las métricas de la nueva versión son equivalentes (o mejores) que las de la versión estable. Las métricas críticas:
- Error rate: comparar el porcentaje de errores 5xx entre canary y estable. Si el canary tiene un error rate 2x superior, algo está mal.
- Latencia p95/p99: la latencia media es engañosa. Un 5% de peticiones extremadamente lentas puede esconderse detrás de una media aceptable. El p99 no miente.
- Métricas de negocio: tasa de conversión, pedidos completados, pagos procesados. Un canary que no genera errores técnicos pero reduce las conversiones un 20% es un canary fallido.
El intervalo de observación importa. 10 minutos al 5% con 1.000 peticiones/hora son solo 8 peticiones. Estadísticamente insignificante. Para tener confianza, necesitas un volumen mínimo por paso del canary. La regla práctica: al menos 100 peticiones en el canary antes de avanzar al siguiente paso.
Cuándo no usar canary
Canary no funciona bien para cambios de base de datos. Si la nueva versión requiere un schema migration, el canary y la versión estable leen la misma base de datos. El nuevo schema tiene que ser compatible con ambas versiones (expand and contract pattern), lo que limita el tipo de cambios que puedes hacer incrementalmente.
Tampoco funciona cuando los cambios afectan a estado compartido (caches, colas) de formas incompatibles. Si la versión canary produce mensajes en un formato que la versión estable no puede consumir, el 5% de tráfico canary puede corromper datos para el otro 95%.
Feature flags: el interruptor granular
Los feature flags desacoplan el despliegue del lanzamiento. Despliegas código nuevo en producción pero desactivado. Lo activas para usuarios específicos, para un porcentaje de tráfico, o para nadie (dark launch). Esto permite desplegar continuamente sin riesgo y lanzar cuando el negocio lo decide.
Tipos de feature flags
Release flags: activan funcionalidades nuevas. El caso más común. “Mostrar el nuevo checkout a los usuarios del segmento beta.” Vida corta: se activan, se validan, y se eliminan (junto con el código del path antiguo).
Experiment flags: para A/B testing. “El 50% de los usuarios ve el botón azul, el 50% el verde.” Se mantienen hasta que hay resultados estadísticamente significativos.
Operational flags: circuit breakers manuales. “Si el servicio de pagos tiene problemas, mostrar el mensaje de mantenimiento.” Sin fecha de eliminación. Son infraestructura permanente.
Permission flags: habilitan funcionalidades por usuario o segmento. “Los usuarios premium ven el dashboard avanzado.” Cercanos a la gestión de permisos, pero implementados como flags para mayor flexibilidad.
Herramientas
LaunchDarkly es el líder del mercado (valorado en 3.000 millones $). SDKs para todos los lenguajes, targeting avanzado, evaluación del lado del servidor con streaming. Desde 8.33 $/mes por seat (plan Starter). Para equipos de 10+, el coste escala rápidamente.
Unleash es la alternativa open-source más madura. Self-hosted o cloud. Soporta targeting, gradual rollouts y variantes. Para equipos que no quieren dependencia de un SaaS para algo tan crítico como los feature flags.
Flagsmith, OpenFeature, y el propio AWS AppConfig con feature flags son opciones intermedias.
Nuestra recomendación: para equipos de hasta 20 desarrolladores, Unleash self-hosted. Coste cero de licencia, control total, y suficiente funcionalidad para el 90% de los casos. LaunchDarkly para organizaciones grandes donde el soporte y la integración con herramientas enterprise justifiquen el coste.
La deuda técnica de los feature flags
Un feature flag que se queda en el código 6 meses después de su lanzamiento es deuda técnica. Cada flag añade un path condicional que hay que mantener y testear. Con 50 flags activos, las combinaciones posibles son astronómicas.
Regla estricta: todo feature flag de release tiene una fecha de eliminación asignada en el momento de crearlo. En nuestros proyectos, usamos un bot que alerta cuando un flag supera los 30 días de antigüedad sin ser removido. Sin esta disciplina, hemos visto codebases con más de 200 flags, donde nadie sabía cuáles estaban activos y cuáles eran vestigios de features lanzadas hace dos años.
Progressive rollouts: el modelo completo
Canary y feature flags se combinan en progressive rollouts: un modelo de despliegue donde el código se expone a usuarios reales de forma gradual y controlada.
El flujo típico:
- Deploy con feature flag desactivado (dark launch)
- Activar para el equipo interno (dogfooding)
- Ampliar al 1% de usuarios reales
- Observar métricas durante 24 horas
- Ampliar al 10%, observar 24 horas
- Ampliar al 50%, observar 24 horas
- Full rollout (100%)
- Limpieza: eliminar el feature flag y el código del path antiguo
Cada paso tiene criterios de avance (métricas dentro de umbrales) y criterios de reversión (métricas fuera de umbrales). La automatización completa es posible con herramientas como Argo Rollouts + Prometheus + feature flag service, pero incluso manual el modelo reduce drásticamente el riesgo.
¿Suena lento? Lo es. Un feature que antes se desplegaba en un día ahora tarda una semana en llegar al 100%. Pero el número de incidentes en producción se reduce proporcionalmente. En un cliente con despliegues diarios, pasar de “deploy and pray” a progressive rollouts redujo los incidentes post-deploy un 85%.
Chaos engineering: romper para fortalecer
Chaos engineering es la práctica de introducir fallos deliberados en producción para verificar que el sistema los tolera. No es testing destructivo aleatorio. Es experimentación controlada con hipótesis claras.
El modelo científico
Un experimento de chaos engineering sigue el método científico:
- Hipótesis: “Si una instancia del servicio de pagos falla, el load balancer redirige el tráfico a las instancias sanas y los usuarios no experimentan errores.”
- Variables: ¿qué fallo? (kill del proceso, latencia inyectada, partición de red). ¿Qué medimos? (error rate, latencia, disponibilidad).
- Blast radius: ¿cuántos usuarios pueden verse afectados? Empezar con blast radius mínimo.
- Ejecutar: introducir el fallo.
- Observar: ¿la hipótesis se cumple?
- Aprender: si no se cumple, ¿por qué? ¿Qué hay que mejorar?
Herramientas
Chaos Monkey de Netflix es la herramienta original: mata instancias de VM aleatoriamente en producción. Simple pero efectivo para validar que los servicios toleran la pérdida de instancias.
Litmus Chaos es el proyecto CNCF para chaos engineering en Kubernetes. Soporta experimentos como pod kill, network delay, disk fill, y CPU stress. Se define como recursos de Kubernetes (ChaosEngine, ChaosExperiment), lo que facilita la integración con CI/CD.
Gremlin es la opción SaaS más completa: interfaz web, targeting preciso, halt button para detener el experimento inmediatamente. Desde 2.000 $/año para equipos pequeños.
AWS Fault Injection Simulator (FIS) permite inyectar fallos en servicios AWS (parar instancias EC2, throttlear DynamoDB, desconectar subnets). Nativo, sin agentes, fácil de configurar para equipos que ya están en AWS.
Por dónde empezar
No empieces matando instancias en producción el primer día. El camino incremental:
Nivel 1 - Game days: simulacros manuales en un entorno no productivo. “¿Qué pasa si el servicio X deja de responder?” El equipo investiga y documenta el impacto. Cero automatización, máximo aprendizaje.
Nivel 2 - Chaos automatizado en staging: ejecutar experimentos de Litmus o FIS en staging de forma automática. Validar que los runbooks de respuesta funcionan.
Nivel 3 - Chaos en producción con blast radius mínimo: matar un pod de un servicio no crítico en producción durante horario laboral, con el equipo observando. Verificar que el auto-scaling y el health check funcionan.
Nivel 4 - Chaos continuo en producción: ejecutar experimentos automáticos periódicamente (semanalmente, por ejemplo) contra servicios críticos. El sistema debería tolerar estos fallos sin intervención humana.
La mayoría de los equipos nunca pasan del nivel 2. Y está bien. Los game days manuales ya generan un valor enorme al exponer suposiciones incorrectas sobre la resiliencia del sistema.
La cultura detrás de las herramientas
Testing en producción requiere una cultura organizacional específica. Los equipos que lo hacen bien comparten tres características:
Confianza en la observabilidad: si no puedes ver el impacto de un cambio en tiempo real, no puedes testear en producción de forma segura. Los dashboards, las alertas y las trazas son prerequisitos, no extras.
Reversión rápida como prioridad: el tiempo para revertir un deploy debe ser inferior a 5 minutos. Si revertir requiere un proceso manual de 30 minutos, el riesgo del testing en producción es inaceptable. Automatiza la reversión antes de automatizar el despliegue.
Blameless culture: cuando un canary falla y hay que revertir, eso no es un error. Es el sistema funcionando como se diseñó. Si el equipo teme desplegar porque un rollback se percibe como fracaso, nadie desplegará incrementalmente.
Testing en producción no reemplaza el testing previo. Complementa un pipeline de CI/CD robusto con unit tests, integration tests y testing en staging. Es la última capa de validación, la que verifica que el sistema funciona con la única variable que no puedes simular: la realidad.
Nuestro equipo de cloud y DevOps implementa pipelines de despliegue con canary, feature flags y progressive rollouts. Si tu organización quiere reducir los incidentes post-deploy, podemos diseñar la estrategia de testing en producción adecuada a tu stack y equipo. Consulta también nuestro artículo sobre observabilidad en microservicios para los prerequisitos de monitoring necesarios.