Todo sistema vai a produção com a promessa implícita de estar disponível. Quando uma atualização quebra isso — mesmo por dois minutos — usuários perdem transações, pipelines de pagamento falham no meio, e sessões ativas caem sem aviso. Em sistemas com SLA de 99,9%, dois minutos de downtime por semana já violam o contrato. Em sistemas financeiros ou de saúde, o custo é mais concreto que isso.
A ideia por trás do zero-downtime é simples: nunca há um momento em que nenhuma instância saudável está servindo tráfego. A complexidade está em como garantir isso enquanto o código muda, o banco de dados migra, e a configuração evolui — às vezes tudo ao mesmo tempo.
As três estratégias que importam
Rolling deployment é o padrão mais comum e o ponto de partida natural. As instâncias são atualizadas em grupos — digamos, 25% de cada vez — enquanto as restantes continuam servindo. O load balancer direciona tráfego apenas para instâncias saudáveis; se uma falhar nos health checks após a atualização, o rollout para. É o comportamento padrão do Kubernetes com um Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # nunca reduz capacidade
maxSurge: 1 # sobe uma instância nova antes de derrubar uma velha
template:
spec:
containers:
- name: api
image: minha-api:v2
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 3
O readinessProbe é o detalhe que faz isso funcionar de verdade: o Kubernetes só manda tráfego para um pod quando ele responde como saudável. Sem isso, requisições chegam em instâncias que ainda estão inicializando.
Blue-green deployment mantém dois ambientes idênticos — blue rodando a versão atual, green recebendo a nova. Quando o green está pronto e validado, o load balancer muda o tráfego de uma vez. Rollback é instantâneo: basta apontar de volta para o blue. O custo é dobrar a infraestrutura durante o deploy, o que em clouds modernas é temporário e aceitável.
// Exemplo simplificado de troca via AWS SDK
import { ElasticLoadBalancingV2Client, ModifyListenerCommand } from '@aws-sdk/client-elastic-load-balancing-v2';
const client = new ElasticLoadBalancingV2Client({ region: 'us-east-1' });
async function switchTraffego(listenerArn, greenTargetGroupArn) {
await client.send(new ModifyListenerCommand({
ListenerArn: listenerArn,
DefaultActions: [{
Type: 'forward',
TargetGroupArn: greenTargetGroupArn,
}],
}));
console.log('Tráfego redirecionado para o ambiente green');
}
Canary release é blue-green com granularidade: em vez de migrar 100% do tráfego de uma vez, você começa com 5%, observa métricas por alguns minutos ou horas, e vai aumentando gradualmente. Se as taxas de erro subirem ou a latência piorar, você reverte antes de afetar a maioria dos usuários. É a estratégia que melhor equilibra velocidade de deploy com controle de risco.
# Ajuste de peso via boto3 — 10% para canary, 90% para stable
import boto3
elbv2 = boto3.client('elbv2')
elbv2.modify_listener(
ListenerArn='arn:aws:elasticloadbalancing:...',
DefaultActions=[{
'Type': 'forward',
'ForwardConfig': {
'TargetGroups': [
{'TargetGroupArn': 'arn:...stable', 'Weight': 90},
{'TargetGroupArn': 'arn:...canary', 'Weight': 10},
],
'TargetGroupStickinessConfig': {'Enabled': True, 'DurationSeconds': 300}
}
}]
)
O que o código não resolve sozinho
Estratégias de deploy cuidam do tráfego e das instâncias. Mas zero-downtime tem uma dimensão que vive fora do código da aplicação: migrações de banco de dados.
Adicionar uma coluna com NOT NULL sem valor padrão em uma tabela com milhões de linhas trava o banco inteiro por minutos em PostgreSQL — independente de quantos pods Kubernetes você tenha. O padrão para evitar isso é expand/contract: primeiro você adiciona a coluna como nullable (expand), deploya a aplicação que escreve nos dois formatos, depois preenche os valores existentes em background, adiciona a constraint, e por fim remove o código de compatibilidade (contract). São três deploys onde antes havia um, mas nenhum deles causa downtime.
O mesmo princípio vale para renomear colunas, trocar tipos, e remover campos. A versão nova do código não pode assumir que a migração já rodou — especialmente em rolling deployments, onde v1 e v2 da aplicação coexistem por alguns minutos.
Outro ponto que escapa nos planejamentos: conexões longas. Quando um pod é marcado para terminar, o Kubernetes envia SIGTERM e aguarda o terminationGracePeriodSeconds antes de forçar a morte. Se a aplicação não trata esse sinal, requisições em andamento são cortadas no meio. O tratamento correto é parar de aceitar novas conexões ao receber SIGTERM, deixar as existentes terminarem, e só então sair.
// Graceful shutdown em Node.js
const server = app.listen(8080);
process.on('SIGTERM', () => {
server.close(() => {
// conexões existentes drenaram, pode sair
process.exit(0);
});
});
Monitoramento não é opcional nesse contexto — é parte da estratégia. Um canary release sem observabilidade é só um deploy com nome diferente. O que você precisa acompanhar durante qualquer rollout: taxa de erro por versão, latência de p95 e p99, e health checks de readiness. Se qualquer uma dessas métricas piorar durante o rollout, o processo deve parar automaticamente — não esperar alguém perceber no Slack.
Kubernetes tem maxUnavailable: 0 e maxSurge para controlar isso no nível de pods. Para canary com controle mais fino, ferramentas como Argo Rollouts ou Flagger automatizam a progressão baseada em métricas do Prometheus: se o error rate do canary ficar abaixo de 1% por 10 minutos, sobe para 25%; se passar de 2% em qualquer janela, reverte sozinho.
O objetivo final não é deploy sem downtime por sorte — é deploy sem downtime por design, onde o sistema detecta e reage a problemas antes que afetem usuários o suficiente para importar.
Referências
- Kubernetes. Deployments. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Argo Rollouts. Canary Deployments. https://argoproj.github.io/argo-rollouts/
- Flagger. Automated canary deployments. https://flagger.app/
- Fowler, M. BlueGreenDeployment. https://martinfowler.com/bliki/BlueGreenDeployment.html
- Netflix. Simian Army. https://github.com/Netflix/simianarmy/wiki