Pipeline de CD: deploy automático

1. Introdução à Entrega Contínua (CD) no Contexto DevOps

A Entrega Contínua (CD) é o estágio do pipeline DevOps que automatiza a implantação de aplicações em ambientes de produção ou staging. Enquanto a Integração Contínua (CI) foca em compilar, testar e validar o código, a CD leva o artefato final — uma imagem Docker — diretamente para o cluster Kubernetes, eliminando intervenções manuais.

A diferença fundamental entre CI e CD está no destino: a CI termina com um artefato pronto (imagem no registry), enquanto a CD inicia a partir desse artefato e o implanta em um cluster. Com Docker e Kubernetes, o deploy automático ganha consistência (mesma imagem em todos os ambientes) e escalabilidade (orquestração nativa de containers).

O fluxo completo é: código commitado → trigger do pipeline → build da imagem Docker → push para registry → atualização do deployment no Kubernetes → validação pós-deploy.

2. Preparando o Ambiente para Deploy Automático

Antes de configurar o pipeline, é necessário ter um cluster Kubernetes acessível. Para desenvolvimento local, use Minikube:

minikube start --cpus 4 --memory 8192

Para ambientes cloud, crie um cluster EKS (AWS), GKE (GCP) ou AKS (Azure). Instale o kubectl e configure a autenticação no runner do GitHub Actions. Crie um namespace dedicado:

kubectl create namespace production

O kubeconfig do cluster deve ser armazenado como secret no GitHub para uso no pipeline.

3. Construindo e Publicando a Imagem Docker no Pipeline

O build da imagem deve usar Dockerfile multi-stage para reduzir o tamanho final. Exemplo para uma aplicação Node.js:

# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Runtime
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

A tag da imagem deve combinar versão semântica com o SHA do commit para rastreabilidade:

docker build -t myapp:1.2.3-${GITHUB_SHA::7} .
docker tag myapp:1.2.3-${GITHUB_SHA::7} registry.example.com/myapp:1.2.3-${GITHUB_SHA::7}
docker push registry.example.com/myapp:1.2.3-${GITHUB_SHA::7}

4. Gerenciando Secrets e Configurações para Deploy

No GitHub Actions, armazene secrets como DOCKER_PASSWORD, KUBE_CONFIG e REGISTRY_URL. Para injetar configurações no Kubernetes, use ConfigMaps e Secrets:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  NODE_ENV: "production"
  API_URL: "https://api.example.com"
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: production
type: Opaque
data:
  DB_PASSWORD: <base64-encoded-password>

Para ambientes mais avançados, integre com External Secrets Operator (AWS Secrets Manager, Google Secret Manager).

5. Estratégias de Deploy no Kubernetes

Rolling Update (padrão)

Atualiza pods gradualmente com zero downtime:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    spec:
      containers:
      - name: myapp
        image: registry.example.com/myapp:latest

Blue/Green Deploy

Usa dois Deployments (blue e green) e um Service que aponta para o ativo:

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
    version: blue   # ou green
  ports:
  - port: 80
    targetPort: 3000

Canary Deploy

Distribui tráfego gradualmente entre versões usando Service Mesh como Istio:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - myapp.example.com
  http:
  - match:
    - headers:
        canary:
          exact: "true"
    route:
    - destination:
        host: myapp-canary
        port:
          number: 80
      weight: 10
  - route:
    - destination:
        host: myapp-stable
        port:
          number: 80
      weight: 90

6. Implementando o Workflow de CD no GitHub Actions

Arquivo .github/workflows/deploy.yml:

name: CD Pipeline

on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY_URL }}
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build and Push
        run: |
          IMAGE_TAG="${{ github.ref_name }}-${{ github.sha::7 }}"
          docker build -t myapp:$IMAGE_TAG .
          docker tag myapp:$IMAGE_TAG ${{ secrets.REGISTRY_URL }}/myapp:$IMAGE_TAG
          docker push ${{ secrets.REGISTRY_URL }}/myapp:$IMAGE_TAG

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure kubectl
        run: |
          echo "${{ secrets.KUBE_CONFIG }}" > kubeconfig
          export KUBECONFIG=kubeconfig
      - name: Deploy to Kubernetes
        run: |
          IMAGE_TAG="${{ github.ref_name }}-${{ github.sha::7 }}"
          kubectl set image deployment/myapp myapp=${{ secrets.REGISTRY_URL }}/myapp:$IMAGE_TAG -n production
      - name: Verify Deployment
        run: |
          kubectl rollout status deployment/myapp -n production --timeout=5m

Para pipelines mais complexos, use helm upgrade:

helm upgrade myapp ./charts/myapp \
  --set image.tag=$IMAGE_TAG \
  --namespace production

7. Validação e Rollback Automático

Configure health checks no manifesto do Deployment:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: myapp
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 3

No pipeline, adicione monitoramento pós-deploy:

- name: Monitor Deployment
  run: |
    kubectl logs deployment/myapp -n production --tail=50
    kubectl get pods -n production -l app=myapp

Rollback automático em caso de falha:

- name: Rollback on Failure
  if: failure()
  run: |
    kubectl rollout undo deployment/myapp -n production
    echo "Deploy falhou. Rollback executado."

8. Boas Práticas e Próximos Passos

  • Imutabilidade: nunca altere pods manualmente no cluster. Sempre passe pelo pipeline.
  • Versionamento de manifestos: mantenha YAMLs do Kubernetes no mesmo repositório do código.
  • Observabilidade: integre com Prometheus para métricas e Grafana para dashboards.

Próximos passos incluem:
- Implementar approval gates manuais para produção
- Usar ArgoCD para GitOps (deploy declarativo a partir do Git)
- Adicionar testes de integração pós-deploy automatizados

Referências