Como fazer deploy canário em Kubernetes com GitHub Actions: passo a passo
Este tutorial mostra como fazer um deploy canário em Kubernetes com GitHub Actions para implementar novas versões gradualmente e reduzir o risco. Explico por que o deploy canário é útil; de seguida detalho um fluxo concreto com manifestos Kubernetes, GitHub Actions e verificação simples.
Pré-requisitos
- Conta no GitHub e repositório com o código da aplicação (ex.: imagem Docker pública ou registada).
- Cluster Kubernetes acessível (minikube, kind ou cluster na cloud) com o kubectl configurado.
- Runner do GitHub Actions com permissões para o kubectl (use secrets KUBECONFIG ou um token).
- Conhecimentos básicos de Kubernetes: Deployment, Service e labels.
Passo 1: Preparar manifestos Kubernetes para suporte a canário
Crie um Deployment principal e prepare um Deployment separado para o canário. A ideia é ter dois Deployments (app-primary, app-canary) e um Service que balanceie por label. Assim conseguimos controlar o tráfego para o canário alterando réplicas ou weights no Ingress/Service.
# deployment-primary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-primary
spec:
replicas: 3
selector:
matchLabels:
app: myapp
role: primary
template:
metadata:
labels:
app: myapp
role: primary
spec:
containers:
- name: myapp
image: myrepo/myapp:stable
ports:
- containerPort: 80
# deployment-canary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
role: canary
template:
metadata:
labels:
app: myapp
role: canary
spec:
containers:
- name: myapp
image: myrepo/myapp:canary
ports:
- containerPort: 80
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 80
type: ClusterIP
Passo 2: Configurar GitHub Actions para criar imagem e fazer deploy canário
Crie um workflow que constrói a imagem canary, faz push para o registry e aplica os manifestos ao cluster. Use um job que actualiza apenas o Deployment canary para a nova tag; assim o primary mantém a versão estável.
# .github/workflows/canary-deploy.yaml
name: Canary Deploy
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push image
uses: docker/build-push-action@v4
with:
push: true
tags: myrepo/myapp:${{ github.sha }}
# configure registry credentials via secrets
- name: Configure kubectl
run: |
echo "$KUBECONFIG" > kubeconfig
export KUBECONFIG=$PWD/kubeconfig
env:
KUBECONFIG: ${{ secrets.KUBECONFIG }}
- name: Update canary deployment image
run: |
kubectl set image deployment/app-canary myapp=myrepo/myapp:${{ github.sha }}
kubectl rollout status deployment/app-canary --timeout=60s
Passo 3: Gradualmente aumentar o tráfego para o canário
Há várias formas de aumentar o tráfego: aumentar as réplicas do canário, usar Ingress/Service com weights (ex.: Istio, Traefik) ou manipular selectors. Aqui mostramos a forma simples: aumentar as réplicas do canário e, mais tarde, reduzir as do primary.
# scale-canary.sh (executar via GitHub Action ou manualmente)
kubectl scale deployment/app-canary --replicas=2
# após verificação
kubectl scale deployment/app-primary --replicas=2
# finalmente promover o canário para primary alterando images e restaurando réplicas
kubectl set image deployment/app-primary myapp=myrepo/myapp:${CANARY_TAG}
kubectl scale deployment/app-canary --replicas=0
kubectl scale deployment/app-primary --replicas=3
Passo 4: Monitorização e rollback automático
Configure health checks liveness/readiness e use um script simples para verificar métricas (erros, latência) ou o estado de readiness. No exemplo abaixo, um passo do workflow verifica endpoints e faz rollback se a taxa de erro subir.
# exemplo simplificado de verificação via curl
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://myapp-svc/health)
if [ "$STATUS" != "200" ]; then
kubectl set image deployment/app-canary myapp=myrepo/myapp:stable
kubectl rollout status deployment/app-canary --timeout=60s
exit 1
fi
Verificar o resultado
Confirme que o canário está a correr a nova imagem e a servir tráfego apenas para parte dos utilizadores. Use kubectl para inspecionar:
kubectl get deployments
kubectl get pods -l role=canary -o wide
kubectl describe deployment app-canary
kubectl logs deployment/app-canary --tail=50
Se usar um Ingress ou Service com weight, verifique métricas no controlador de Ingress ou nas ferramentas de observabilidade (Prometheus/Grafana). Teste endpoints e confirme que o rollback funciona simulando falhas.
Conclusão
O deploy canário em Kubernetes com GitHub Actions permite reduzir o risco de releases, controlando gradualmente o tráfego. Próximos passos: integrar Istio/Linkerd para traffic shifting por weight, automatizar métricas com Prometheus e criar gates automáticos no workflow. Dica: comece com réplicas e health checks simples antes de introduzir um service mesh — qual é a maior preocupação que pretende mitigar com canários?