O que é canary deployment? Um guia prático para devs

Resumo

Um canary deployment envia a nova versão para uma pequena parcela do tráfego real, muitas vezes de 1% a 5%, antes de todos a receberem. Você compara a taxa de erro e a latência com a versão estável, amplia a fatia se tudo estiver bem e zera o peso do canário se não estiver. Ele limita o dano de uma release ruim, mas exige métricas por versão e tráfego suficiente para que o resultado signifique alguma coisa.

Mesa de desenvolvedor à noite com painel de gráficos de tráfego e uma pequena figura de canário amarela

O que é canary deployment? É um lançamento em que a nova versão da sua aplicação recebe primeiro uma pequena fatia do tráfego real, digamos de 1% a 5%, enquanto todos os outros continuam na versão antiga. Você acompanha a taxa de erro e a latência nessa fatia. Se ela parecer saudável, você amplia. Se parecer ruim, devolve o tráfego para a versão estável e quase ninguém percebe. Essa é a ideia, e o resto do artigo mostra como fazê-la funcionar na prática.

An old miner's lantern and empty birdcage on a workbench, the origin of the canary name

Por que se chama canary?

Mineiros levavam canários para dentro das minas porque a ave reagia ao gás tóxico antes das pessoas. Um canário que parava de cantar era o sinal para sair. No deploy a lógica é parecida: um pequeno grupo de usuários encontra o código novo primeiro e funciona como alerta precoce. O glossário da CNCF descreve o método como dois ambientes, um servindo o tráfego real e outro com o código atualizado, com o tráfego sendo transferido aos poucos, começando por uma fatia pequena como 1%.

Na prática, o detalhe que importa é que os usuários do canário são usuários reais. Staging não reproduz isso. Produção tem navegadores estranhos, caches desatualizados e aquele cliente com um arquivo de importação de 40 MB. O canário é a forma de encontrar esses casos antes que todos encontrem o seu bug.

Como um canary deployment funciona de fato?

São quatro peças, nada exótico.

Uma rampa típica fica assim: 1%, 5%, 25%, 50%, 100%, com uma pausa em cada degrau. A documentação do Google Cloud Deploy descreve a mesma forma: você define uma sequência de percentuais e a ferramenta distribui o tráfego, com um exemplo que usa fases de 25%, 50% e 75% antes da versão estável final. A documentação de canary do Cloud Deploy também mostra que cada fase pode rodar um job de verificação e uma etapa de análise para decidir se avança.

Não é uma configuração perfeita, mas é viável. Você não precisa de Kubernetes para isso. Uma rota ponderada no nginx, uma regra de Cloudflare Worker que grava um cookie ou duas máquinas no Fly.io atrás de um mesmo proxy, tudo isso conta.

Como fica o divisor de tráfego em uma configuração?

Aqui vai o menor exemplo útil: um upstream do nginx com pesos. Nove em cada dez requisições vão para a estável, uma vai para o canário.

upstream app {
    server 10.0.0.10:3000 weight=9;   # estável
    server 10.0.0.11:3000 weight=1;   # canário
}

Esse exemplo tem uma falha que você precisa conhecer: a divisão é por requisição, então um mesmo usuário pode alternar entre versões em cliques seguidos. Se a nova versão muda o formato de uma resposta de API ou de uma coluna do banco, esse usuário vai ter uma experiência ruim. Roteamento fixo por cookie ou por ID de usuário resolve isso, e é a primeira coisa que vale adicionar depois que a divisão básica funciona.

Laptop showing two diverging metric lines comparing a stable and a canary release

O que observar enquanto o canário roda?

Compare o canário com a versão estável no mesmo momento, e não com a semana passada, porque a semana passada tinha outro tráfego. A pergunta é sempre: o canário está pior do que a versão que atende os outros 95% agora?

O erro mais comum em times pequenos é avançar por cronômetro: cinco minutos em 1%, depois 25%, independentemente do que os gráficos mostram. Com pouco tráfego, cinco minutos em 1% podem ser seis requisições, e isso não diz nada. Espere um número mínimo de requisições, e não um número mínimo de minutos.

Ferramentas que automatizam essa parte valem uma olhada quando você já tem tráfego real.

Canary ou blue-green: qual escolher?

Blue-green mantém dois ambientes completos e troca todo o tráfego de uma vez. O rollback é desfazer a troca, rápido e limpo. O custo é que, por um instante, 100% dos usuários estão na versão nova, e você paga pela infraestrutura dobrada durante a troca.

O canary expõe só uma fatia, então o raio de impacto é menor. O preço é a complexidade: você precisa de divisão de tráfego, métricas por versão e uma regra de decisão. O rollback significa zerar o peso do canário, o que é rápido, mas não é literalmente instantâneo se as conexões precisarem ser drenadas.

Três motivos para escolher canary e um para não escolher. Use canary quando um bug em produção sai caro, quando você tem tráfego suficiente para que uma fatia pequena signifique algo e quando consegue comparar métricas por versão. Evite quando você tem algumas dezenas de usuários por dia: a fatia do canário vai estar estatisticamente vazia e você vai estar chutando. Nessa escala, blue-green, ou até um deploy simples com um script de rollback rápido, é a resposta honesta.

Os rolling updates ficam no meio do caminho. Eles substituem instâncias uma a uma, o que é suave, mas não são um experimento controlado: você não escolhe quem vê a versão nova nem compara grupos.

Onde entram as feature flags?

Um canary deployment divide o tráfego entre versões do código. Uma feature flag divide o comportamento dentro de uma mesma versão. As pessoas confundem os dois, e a confusão sai cara.

Faça o deploy do código novo para todo mundo, escondido atrás de uma flag desligada. Depois ligue a flag para 1% dos usuários, depois 10%, depois todos. Isso costuma ser chamado de canary release no nível da funcionalidade. A vantagem é que o rollback vira desligar a flag, sem novo deploy. A desvantagem é que o caminho de código morto fica em produção para todo mundo, e flags esquecidas viram dívida técnica.

Para um dev solo, flags costumam ser o primeiro passo mais barato. Um booleano em uma tabela de configuração e um hash do ID do usuário já entregam uns 80% do valor. Se você crescer além disso, um serviço gerenciado cuida de segmentação, logs de auditoria e liberações graduais por porcentagem.

A rotary dial turned up slightly, like shifting a small share of traffic to a new version

O que dá errado com canaries em projetos reais?

Testado, não é ótimo. Mesmo assim, veja por que continuamos fazendo. Estas são as falhas que de fato mordem.

Migrações de banco. As duas versões acessam o mesmo banco ao mesmo tempo. Se o canário remove ou renomeia uma coluna, a estável quebra. A correção é o padrão expand and contract: adicione a coluna nova primeiro, envie código que lida com as duas formas e só remova a antiga em uma release posterior. Pular isso faz o seu canário derrubar a versão estável.

Sessões com estado. Se as sessões vivem na memória de uma instância, um usuário que alterna entre versões é deslogado. Mova o estado da sessão para um armazenamento compartilhado antes de tentar canaries.

Cache envenenado. Uma versão nova que grava outro formato de cache pode corromper o que a versão antiga lê. Versione as chaves do cache.

Jobs em segundo plano. O canário também consome mensagens de fila. Um worker com bug pode consumir jobs na velocidade máxima, porque a porcentagem de tráfego não limita o consumo da fila. Dê ao canário a sua própria fila ou um peso de consumidor.

Alertas que ninguém configurou. O canário pode falhar de forma barulhenta em um painel que ninguém abre. Um aborto automático por limiar vence um humano olhando a tela, principalmente às 2h da manhã em São Paulo, quando a única pessoa acordada é quem fez o deploy.

Como começar com um canary em um projeto pessoal?

Comece menor do que você acha que deveria. Você é um dev, não um time de plataforma.

  1. Marque cada métrica com uma versão. Coloque o SHA do git em um header e nos logs. Sem isso, você não consegue comparar canário e estável.

  2. Escolha uma regra de aborto. Por exemplo: taxa de erro do canário acima de 2x a da estável por cinco minutos significa rollback. Uma regra só, escrita.

  3. Adicione uma rota ponderada. Pesos no nginx, uma regra na Cloudflare ou o recurso de divisão de tráfego da sua hospedagem. A maioria das plataformas gerenciadas já oferece roteamento por porcentagem sem ferramentas extras.

  4. Envie algo simples primeiro. Uma mudança de texto, e não a reescrita da página de preços. Pratique a rampa e o rollback quando nada está em jogo.

  5. Cronometre o rollback. Execute de verdade pelo menos uma vez. Se levar dez minutos de tentativas e erros, isso é o que precisa ser consertado, e não a rampa.

Se o seu projeto ainda está na fase de descobrir quem paga por ele, isso provavelmente é cedo demais. Publique de forma simples, mantenha um script de rollback e volte aos canaries quando uma queda puder custar clientes de verdade. Se você já está nessa fase, a rota ponderada somada a uma regra de aborto é um fim de semana de trabalho, e se paga na primeira vez que uma release ruim morre em 1% em vez de 100%.

Vale usar canary para tudo?

Não. Mudanças de configuração, ajustes de texto e a correção de um erro de digitação no rodapé não precisam de rampa. Use canary nas mudanças em que errar custa dinheiro ou confiança: pagamentos, autenticação, modelos de dados e qualquer coisa no caminho quente. Um pipeline que faz rampa em todo commit, levando uma hora, vai ser ignorado na primeira vez que alguém tiver pressa, e um processo ignorado é pior do que processo nenhum.

Então, qual é a mudança mais arriscada da sua próxima release, e o que seria preciso para mandá-la para 1% dos usuários primeiro?

Perguntas frequentes

O que é um canary deployment, em termos simples?
É um método de release em que a nova versão atende primeiro uma pequena porcentagem de usuários reais, enquanto o restante continua na versão antiga. Se as métricas se mantêm saudáveis, a fatia cresce até a nova versão atender todos. Se piorarem, o tráfego volta para a versão estável.
Com qual porcentagem de tráfego um canário deve começar?
Muitos times começam entre 1% e 5%. O número certo depende do volume: a fatia precisa gerar requisições suficientes para comparar taxa de erro e latência. Com tráfego muito baixo, espere um número mínimo de requisições, e não um número fixo de minutos.
Qual é a diferença entre canary e blue-green deployment?
O blue-green roda dois ambientes completos e troca todo o tráfego de uma vez, então o rollback é desfazer a troca. O canary desloca o tráfego gradualmente, o que expõe menos usuários a uma release ruim, mas exige ponderação de tráfego e monitoramento por versão.
Canary deployment é o mesmo que feature flag?
Não. O canary divide o tráfego entre duas versões implantadas do código. A feature flag liga ou desliga um comportamento dentro de uma única versão. Os dois combinam bem: você implanta escondido atrás de uma flag e depois a ativa para uma pequena porcentagem de usuários.
Precisa de Kubernetes para fazer canary deployments?
Não. Upstreams ponderados no nginx, uma regra de CDN ou de borda, ou a divisão de tráfego de uma hospedagem gerenciada também fazem isso. As ferramentas do Kubernetes facilitam rampas e análises automáticas, mas não são obrigatórias.
Como funcionam as migrações de banco com releases canary?
As duas versões compartilham um único banco, então use o padrão expand and contract: adicione primeiro as colunas novas, envie código que lida com as duas formas e remova as colunas antigas apenas em uma release posterior.