Deployments Canary com Go: como lançar atualizações sem medo e risco
Imagine: você passou anos construindo a arquitetura, escrevendo testes, configurando monitoramento. E então — o lançamento. Um clique, e a nova versão vai para produção. O coração acelera, os dedos tremem. Familiar? E se eu disser que você pode implantar uma nova versão para apenas 5% dos usuários, observar as métricas, e só depois distribuir para todos? Sem downtime, sem pânico, com controle total.
Isso se chama canary deployment (implantação canário). O nome vem dos mineiros que levavam canários consigo — o pássaro morria pelo gás antes das pessoas, alertando sobre o perigo. No mundo DevOps, esses "canários" são os primeiros 5-10% dos usuários que recebem a nova versão. Se algo der errado — revertemos, sem que ninguém perceba o problema.
Neste artigo, vamos explorar como implementar um canary deploy em Go com exemplos reais de código, balanceador de carga e métricas. Vamos nessa!
Por que Go para canary deployment?
Go é uma linguagem criada para microsserviços. Ela compila para um binário estático, não requer dependências no servidor e é facilmente escalável. Mas o principal é que Go tem suporte nativo a concorrência e excelentes bibliotecas para servidores HTTP, tornando-o um candidato ideal para implementar roteamento inteligente de tráfego.
- Desempenho — um servidor Go processa milhares de requisições por segundo em um único núcleo.
- Simplicidade de implantação — um único binário, sem máquinas virtuais ou interpretadores.
- Ecossistema rico — pacotes para métricas (Prometheus), rastreamento (OpenTelemetry) e balanceamento.
Se você já programa em Go e quer automatizar a implantação — a estratégia canary será sua melhor amiga.
Arquitetura do canary deployment em Go
Vamos imaginar que temos um microsserviço em Go que processa requisições de usuários. Normalmente, implantamos uma nova versão em todas as instâncias de uma vez. Com a abordagem canary, executamos a nova versão em paralelo com a antiga, mas direcionamos apenas parte do tráfego para ela.
Aqui está um esquema simplificado:
- Versão estável (v1) — roda em 90% das instâncias.
- Versão canary (v2) — executada em 10% das instâncias.
- Balanceador de carga — distribui o tráfego proporcionalmente.
- Monitoramento — compara métricas (latência, erros, throughput).
- Decisão manual ou automática — distribuímos v2 para 100% ou revertemos.
Isso pode ser implementado de várias formas: via Kubernetes (Service Mesh), via Nginx com pesos personalizados, ou escrevendo seu próprio balanceador em Go. Seguiremos o terceiro caminho — ele oferece controle total e é excelente para aprendizado.
Escrevendo um balanceador de tráfego canary em Go
Vamos escrever um reverse-proxy simples que direcionará requisições para dois backends: stable e canary. O peso da versão canary será definido via configuração ou variável de ambiente.
package main
import ( "log" "math/rand" "net/http" "net/http/httputil" "net/url" "os" "strconv")
type CanaryProxy struct { stable *httputil.ReverseProxy canary *httputil.ReverseProxy canaryWeight int // porcentagem de tráfego para canary (0-100)}
func NewCanaryProxy(stableURL, canaryURL string, weight int) *CanaryProxy { stableTarget, _ := url.Parse(stableURL) canaryTarget, _ := url.Parse(canaryURL)
return &CanaryProxy{ stable: httputil.NewSingleHostReverseProxy(stableTarget), canary: httputil.NewSingleHostReverseProxy(canaryTarget), canaryWeight: weight, }}
func (p *CanaryProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Decisão baseada em número aleatório if rand.Intn(100) <