Destino Dev

Blog

Canary deploy com GitHub Actions em Kubernetes usando Helm e Flagger

Por John Pires · 19 de março de 2026

Canary deploy com GitHub Actions em Kubernetes usando Helm e Flagger

1) Motivacao e trade-offs

Canary deploy reduz risco ao liberar versões incrementais para uma fração do tráfego, permitindo validar métricas reais antes de promoção ampla. Para equipes com 1-3 anos de experiência, implementar Canary com Helm, Flagger e GitHub Actions entrega automação, reprodutibilidade e rollback automático com base em métricas. Porém existem trade-offs:

Menor blast radius vs. maior complexidade operacional. Flagger e Istio/Contour/NGINX adicionam componentes e configuração; pipelines mais longos e observabilidade são obrigatórios. As decisões de rede, métricas e testes determinam se o canary realmente reduz falhas em produção.

Outra troca: rapidez de deploy vs. custo de infra e latência de decisões. Analisar recursos (CPU/mem), tempos de inicialização e tolerância a erros é essencial. Sem métricas corretas, o canary vira apenas roteamento parcial sem proteção real.

Use canary quando você precisa validar mudanças que não são cobertas por testes locais (por exemplo: performance, integração com terceiros, configurações de runtime). Evite canary para deploys triviais com transações idempotentes irrelevantes ao usuário.

Quando usar canary

Use canary para mudanças que impactam disponibilidade, latência, comportamentos estatísticos (caches, circuit-breakers), ou integridade de dados. Não use canary como substituto para testes unitários e de integração; use em conjunto com esses testes.

Principais trade-offs

  • Complexidade: mais entes (istio/flagger/prometheus) a gerenciar.
  • Observabilidade: requisito mínimo — sem métricas apropriadas, canary falha.
  • Automação: pipelines precisam orquestrar imagens, Helm upgrades e monitorar Flagger.
Tip: Não adote canary por modismo. Avalie custo operacional e maturidade do time em deploys e monitoramento.

2) Fundamentos tecnicos

Arquitetura típica: GitHub Actions constrói a imagem, publica no registry, atualiza o chart Helm (ou executa helm upgrade) e aplica a nova imagem ao Kubernetes. Flagger observa o Kubernetes e o serviço mesh / ingress controller para manipular tráfego progressivo. Prometheus fornece métricas, e Alertmanager ou hooks personalizados podem disparar rollbacks.

Componentes envolvidos:

  1. GitHub Actions — CI/CD para build e deploy.
  2. Helm — package e values para parametrizar imagem e recursos.
  3. Flagger — CRDs Canary/AnalysisTemplate para controlar rollouts.
  4. Service mesh ou ingress (Istio, Contour, NGINX): roteamento canário.
  5. Prometheus — métricas (latência, erro, saturação).

O fluxo básico é: Actions → Registry → Helm upgrade (nova imagem tag) → Flagger detecta alteração na Deployment → Flagger cria/trabalha com recurso de tráfego (VirtualService/Ingress) → análise de métricas → promoção ou rollback.

Como Flagger funciona

Flagger monitora mudanças no Deployment alvo. Quando detecta uma nova imagem, ele cria um Canary custom resource e convoca o controller para ajustar pesos de tráfego entre stable e canary. Flagger executa checks configurados (Prometheus queries, webhooks, etc.) em cada etapa e decide subir percentual ou reverter.

Integração com Helm

Helm gerencia as versões do manifesto. A prática recomendada é deixar a imagem parametrizada via values.yaml e disparar um helm upgrade --install com o novo tag. Flagger deve ser capaz de observar Deployments gerados pelo Helm. Em pipelines Idempotentes, use helm diff para prever mudanças e garantir infra como código.

3) Exemplo 1: caso simples

Caso: serviço web stateless chamado web-api. Objetivo: deploy canário de 10% → 50% → 100% com rollback automático se taxa de erro > 1% ou latência p95 > 500ms.

Contexto da infraestrutura

Kubernetes com NGINX Ingress Controller, Prometheus operando e Flagger instalado. Helm charts já configurados para web-api com values.yaml parametrizável.

Padrão de pipeline (GitHub Actions)

Antes do código, explique: este workflow faz build, push para registry (GHCR ou DockerHub), atualiza Helm usando helm upgrade com --set image.tag e espera Flagger executar o canary.

O bloco abaixo é o arquivo .github/workflows/canary.yml. Ele foca em build/push e helm upgrade. Ajuste segredos: DOCKER_USERNAME, DOCKER_PASSWORD, KUBE_CONFIG_DATA.

# .github/workflows/canary.yml
name: canary-deploy
on:
  push:
    branches: [main]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push image
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ghcr.io/myorg/web-api:${{ github.sha }}

      - name: Setup kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: '1.28.0'

      - name: Configure Kubeconfig
        run: |
          echo "${{ secrets.KUBE_CONFIG_DATA }}" | base64 -d > kubeconfig
          export KUBECONFIG=$PWD/kubeconfig

      - name: Helm upgrade
        uses: azure/helm@v1
        with:
          command: upgrade
          chart-type: file
          chart-path: ./charts/web-api
          release-name: web-api
          namespace: production
          args: --install --atomic --set image.tag=${{ github.sha }}

O que esse workflow faz: builda imagem, publica no registry e faz helm upgrade. Depois do helm upgrade, Flagger detecta o novo Deployment e inicia a sequência canária. O step --atomic ajuda a garantir que helm rollback ocorra se helm falhar.

Resultado esperado: novo canary é criado; Flagger controla pesos e realiza validações via Prometheus; se métricas passarem, o canary é promovido para stable.

Exemplo de Canary CRD mínimo

Este Canary custom resource indica os checks básicos. Coloque o arquivo canary.yaml no chart templates ou aplique separadamente.

# canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: web-api
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-api
  service:
    port: 80
  progressDeadlineSeconds: 600
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        threshold: 99
        interval: 1m
      - name: request-duration
        threshold: 500
        interval: 30s

O que esse CRD faz: define a política de rollout. Flagger usará as métricas configuradas para decidir subir o tráfego. maxWeight define o máximo antes da promoção final; stepWeight o incremento por ciclo.

4) Exemplo 2: caso avancado do mundo real

Contexto: microserviço com dependências externas (fila, cache e terceiros), múltiplas equipes e SLAs rígidos. Requer canary com validação de integridade de negócio (synthetic tests), canary em múltiplas regiões e rollout baseado em SLO.

Arquitetura e requisitos

Requisitos práticos:

  • Executar testes sintéticos (end-to-end básicos) contra canary antes de aumentar peso.
  • Verificar métricas customizadas: taxa de erros de integração com terceiros e latência da fila.
  • Implantar canary por região/cluster e coordenar promoção global.

Padrão de implementação

Estratégia recomendada:

  1. Pipeline faz build/push da imagem e atualiza Helm com image.tag.
  2. Flagger inicia canary. Primeiro passo: health checks e readiness.
  3. Executa analysis com métricas Prometheus e um webhook que dispara testes sintéticos contra a URL canary.
  4. Se todos os checks passarem, Flagger incrementa tráfego; se falhar, rollback automático e notificação.

Exemplo de AnalysisTemplate com webhook sintético abaixo.

# analysis-template.yaml
apiVersion: flagger.app/v1beta1
kind: AnalysisTemplate
metadata:
  name: synthetic-e2e
  namespace: production
spec:
  metrics:
  - name: e2e-test
    provider:
      type: web
      url: http://{{.ServiceName}}.production.svc.cluster.local/health/e2e
      timeout: 5s
    threshold: 1
    interval: 30s
    initialDelay: 10s

O que acontece: Flagger ataca o endpoint /health/e2e no pod canary. Se a resposta for OK dentro do timeout, métrica conta como sucesso. Combine com Prometheus para métricas de latência e erro para decisão final.

Para multinúmeros/regiões, mantenha pipelines separados e coordene a promoção via tag de imagem e um job central que aguarda todos os clusters confirmarem promoção. Evite tentar sincronizar tráfego global via Flagger — prefira coordenação por CI.

5) Debugging e troubleshooting

Erros no fluxo canário costumam se originar de problemas em métricas, readiness probes, roteamento ou permissões. Abaixo listamos técnicas práticas para diagnosticar e corrigir.

Logs e eventos

Verifique logs do Flagger e eventos do namespace. Flagger registra decisões e motivos de rollback. Use kubectl -n production logs deploy/flagger e kubectl describe canary web-api -n production para obter contexto.

Métricas e queries Prometheus

Verifique as queries configuradas no Canary CRD. Erros comuns: queries retornam null ou taxa baseada em metrics-server incorreta. Teste queries manualmente no Prometheus UI antes de confiar no canary.

Erros comuns e armadilhas

Listagem de problemas frequentes e soluções práticas:

  • Mismatch nas labels: Flagger não encontra pods porque targetRef não corresponde ao selector do deployment. Solução: alinhar names/labels no Deployment e Canary.
  • Readiness too long: Pods do canary demoram e atrapalham passo de análise. Ajuste readinessProbe e initialDelay na análise.
  • Métricas insuficientes: Queries mal definidas geram falso-positivo. Teste queries e configure intervals maiores para reduzir ruído.
  • Ingress/VirtualService mal configurado: Roteamento entre stable e canary não muda. Verifique recursos de mesh e se Flagger tem permissão para editar VirtualService/Ingress.
  • Rate-limits por CDN/terceiros: Tests sintéticos podem acionar limites. Use circuit-breakers e mocks onde possível.
Tip: Sempre reproduza uma análise manualmente. Se Flagger falha ao aplicar peso, faça um curl direto aos endpoints dos pods canary para validar comportamento.

Comandos úteis

Comandos rápidos que resolvem 80% dos problemas:

# verificar canary
kubectl -n production get canaries
kubectl -n production describe canary web-api

# logs do flagger
kubectl -n flagger-system logs deployment/flagger

# verificar virtualservice (istio) ou ingress
kubectl -n production get virtualservice
kubectl -n production describe virtualservice web-api

# testar promql
# abrir UI do prometheus e testar queries configuradas no canary

O que esses comandos fazem: ajudam a entender em que etapa o rollout está (pending, progressing, aborted), por que um rollback ocorreu e quais métricas falharam.

Conclusao pratico

Canary com GitHub Actions, Helm e Flagger é uma solução robusta para reduzir risco em deploys: automatiza rollout, integra validações reais e permite rollback automático. A chave é investir em métricas corretas, probes realistas e pipelines idempotentes.

Boas práticas resumidas:

  • Parametrize imagens via Helm e use tags imutáveis (sha).
  • Configure métricas Prometheus claras e testadas antes de confiar em rollouts automatizados.
  • Use AnalysisTemplates para casos avançados (synthetic tests, webhooks).
  • Monitore logs do Flagger e eventos do Kubernetes para troubleshooting.

Implementar canary exige setup inicial, mas paga dividendos via menor tempo de recuperação e menos impacto por regressões. Comece com um canary simples e evolua para análise sintética e multi-região conforme maturidade da equipe.

Se implementar, documente o processo no repositório (README) e crie playbooks de rollback e de investigação para reduzir MTTR quando algo falhar.

Assuntos: DevOps, Kubernetes, github-actions, helm, flagger

Leia também