Canary releases: liberação gradual com análise de métricas
1. Fundamentos das Canary Releases no Ecossistema DevOps
Canary releases são uma estratégia de deploy onde uma nova versão de software é liberada gradualmente para um subconjunto de usuários antes de ser disponibilizada para todos. O nome vem da prática histórica de usar canários em minas de carvão como sensores de gás — assim como o pássaro indicava perigo, a versão canary sinaliza problemas antes que afetem toda a base de usuários.
Diferentemente de blue-green deployments (que trocam todo o tráfego entre ambientes idênticos) ou rolling updates (que substituem pods sequencialmente), as canary releases permitem expor apenas uma fração do tráfego à nova versão, possibilitando análise de métricas em tempo real antes de decidir pela promoção ou rollback.
Os princípios fundamentais são: redução de risco, validação em produção com audiência limitada e tomada de decisão baseada em dados observáveis.
2. Arquitetura de Canary no Kubernetes
No Kubernetes, uma canary release típica utiliza dois Deployments — um para a versão estável (stable) e outro para a canary. Ambos compartilham o mesmo Service, mas com labels e selectors que permitem roteamento diferenciado.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-stable
labels:
app: myapp
version: stable
spec:
replicas: 10
selector:
matchLabels:
app: myapp
version: stable
template:
metadata:
labels:
app: myapp
version: stable
spec:
containers:
- name: app
image: myapp:1.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
labels:
app: myapp
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
version: canary
template:
metadata:
labels:
app: myapp
version: canary
spec:
containers:
- name: app
image: myapp:1.1.0
O Service único precisa selecionar ambos os conjuntos de pods:
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 3000
Para roteamento mais granular, utilizamos Service Mesh como Istio ou Linkerd. Com Istio, criamos VirtualServices e DestinationRules para controlar pesos de tráfego.
3. Estratégias de Roteamento de Tráfego
Roteamento por peso
Com Istio, definimos um VirtualService que distribui o tráfego entre as versões:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: app-vs
spec:
hosts:
- app-service
http:
- route:
- destination:
host: app-service
subset: stable
weight: 95
- destination:
host: app-service
subset: canary
weight: 5
E as DestinationRules correspondentes:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: app-dr
spec:
host: app-service
subsets:
- name: stable
labels:
version: stable
- name: canary
labels:
version: canary
Roteamento baseado em cabeçalhos
Para testes A/B, podemos rotear usuários específicos via cookies ou headers:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: app-vs-header
spec:
hosts:
- app-service
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: app-service
subset: canary
- route:
- destination:
host: app-service
subset: stable
4. Métricas e Health Checks para Decisão de Rollout
As métricas críticas para avaliar uma canary release incluem:
- Latência: p50, p95, p99 — aumentos indicam degradação de performance
- Taxa de erro: HTTP 5xx, exceções não tratadas
- Throughput: requisições por segundo (RPS)
- Consumo de recursos: CPU, memória, I/O
Com Prometheus e Grafana, monitoramos em tempo real:
# Exemplo de query Prometheus para taxa de erro
sum(rate(http_requests_total{version="canary", status=~"5.."}[5m]))
/
sum(rate(http_requests_total{version="canary"}[5m]))
Health probes do Kubernetes garantem que pods problemáticos sejam removidos:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
spec:
template:
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 3
5. Automação do Rollout com Análise de Métricas
Ferramentas como Flagger e Argo Rollouts automatizam o progressive delivery. Com Flagger, definimos um recurso Canary que orquestra todo o processo:
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: app-canary
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: app
service:
port: 80
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 1m
webhooks:
- name: load-test
url: http://loadtester.flagger:8080/
timeout: 5s
O Flagger monitora as métricas a cada intervalo. Se os thresholds forem violados, realiza rollback automático. Caso contrário, incrementa o peso da canary até 100%.
6. Exemplo Prático de Canary Release com Docker e Kubernetes
Dockerfile da aplicação (microsserviço Node.js)
FROM node:18-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Aplicação simples com endpoint de métricas
const express = require('express');
const app = express();
const version = process.env.VERSION || '1.0.0';
app.get('/', (req, res) => {
res.json({ version, message: 'Hello from canary!' });
});
app.get('/health', (req, res) => res.status(200).send('OK'));
app.get('/ready', (req, res) => res.status(200).send('Ready'));
app.listen(3000);
Manifesto completo com Flagger Canary
Após instalar o Flagger no cluster, aplicamos:
kubectl apply -f deployment-stable.yaml
kubectl apply -f deployment-canary.yaml
kubectl apply -f service.yaml
kubectl apply -f canary.yaml
O Flagger gerencia automaticamente a progressão do tráfego, monitora métricas do Prometheus e decide por promoção ou rollback.
7. Desafios e Boas Práticas Operacionais
Gerenciamento de estado de sessão: Sessões HTTP ou WebSocket podem quebrar se o tráfego for roteado entre versões. Use sticky sessions (session affinity) no Service ou cookies consistentes.
Cache distribuído: Versões simultâneas podem ter formatos de cache incompatíveis. Utilize versionamento de chave ou cache-sidecar com isolamento.
Migrações de banco de dados: Migrações devem ser backward-compatible por pelo menos duas versões. Estratégias como expand-migrate-contract (expandir schema, migrar dados, contrair schema antigo) são essenciais.
Observabilidade: Combine logs estruturados (JSON), tracing distribuído com Jaeger e dashboards unificados no Grafana para correlação rápida de problemas.
8. Integração com Ferramentas Vizinhas da Série
Canary + Chaos Engineering: Injete falhas controladas (ex: latência, falha de pod) durante o rollout para testar a resiliência da canary. Ferramentas como Chaos Mesh integram-se com Flagger.
Canary + Feature Flags: Use feature flags (LaunchDarkly, Unleash) para ativar/desativar funcionalidades dentro da versão canary, permitindo testes mais granulares sem novo deploy.
Canary + Database Migrations: Ferramentas como Flyway ou Liquibase devem executar migrações em modo "migrate-only" durante a fase canary, garantindo que o schema seja compatível com ambas as versões.
Referências
- Istio Documentation: Traffic Management — Guia oficial sobre VirtualServices, DestinationRules e roteamento de tráfego no Istio.
- Flagger Documentation: Canary Deployments — Tutorial completo de progressive delivery com Flagger e Prometheus.
- Argo Rollouts: Canary Strategy — Documentação oficial do Argo Rollouts para estratégias canary com análise de métricas.
- Prometheus Best Practices: Instrumentation — Guia de melhores práticas para expor métricas em aplicações monitoradas pelo Prometheus.
- Kubernetes Documentation: Configure Liveness, Readiness and Startup Probes — Referência oficial sobre health probes para pods Kubernetes.
- Linkerd: Canary Releases with Traffic Splitting — Tutorial de canary releases utilizando o service mesh Linkerd com análise de métricas.