Projeto final: pipeline completo de CI/CD com Docker e Kubernetes

1. Visão Geral do Projeto e Arquitetura

Este projeto final materializa o ciclo completo de DevOps: desde o commit do código-fonte até o deploy automatizado em um cluster Kubernetes. O pipeline integra as três tecnologias centrais — Docker para containerização, Kubernetes para orquestração e uma ferramenta de CI/CD (GitHub Actions) para automação.

Objetivo do pipeline: garantir que toda alteração no repositório principal passe por validação, empacotamento e entrega contínua ao cluster, com zero intervenção manual.

Componentes do ecossistema:
- Git (GitHub): repositório do código-fonte, Dockerfile e manifestos Kubernetes.
- GitHub Actions: servidor de CI/CD que executa lint, testes, build e push da imagem.
- Docker Registry (Docker Hub): armazenamento das imagens containerizadas.
- Kubernetes (Minikube ou cluster cloud): orquestrador que recebe as atualizações.

Fluxo do pipeline:

1. Desenvolvedor faz push para branch main
2. GitHub Actions detecta o evento e inicia o workflow
3. Executa lint e testes unitários
4. Build da imagem Docker multi-estágio
5. Push da imagem para Docker Hub
6. Atualiza o deployment no Kubernetes com `kubectl set image`
7. Cluster realiza rolling update com health checks
8. Monitoramento e logs são coletados para validação

Cada etapa tem responsabilidade clara: CI valida a qualidade do código e gera o artefato (imagem), CD entrega esse artefato ao cluster com segurança e observabilidade.


2. Preparação do Ambiente de Desenvolvimento e Infraestrutura

Antes de codificar o pipeline, configure o ambiente local ou em nuvem.

Cluster Kubernetes:

# Minikube (local)
minikube start --cpus 4 --memory 8192
kubectl get nodes

# Ou cluster cloud (EKS, GKE, AKS)
# Configure o kubeconfig adequadamente

Docker e Docker Compose:

# Verificar instalação
docker --version
docker-compose --version

Servidor de CI/CD (GitHub Actions):
- Não requer instalação local; o workflow é definido em .github/workflows/.
- Para Jenkins ou GitLab CI, seria necessário provisionar um servidor, mas aqui usaremos GitHub Actions pela simplicidade e integração nativa.


3. Criação e Containerização da Aplicação Exemplo

Estrutura do repositório:

meu-projeto/
├── .github/
│   └── workflows/
│       └── ci-cd-pipeline.yml
├── app/
│   ├── main.py
│   ├── requirements.txt
│   └── test_main.py
├── Dockerfile
├── docker-compose.yml
├── k8s/
│   ├── deployment.yml
│   ├── service.yml
│   └── ingress.yml
└── README.md

Dockerfile multi-estágio (Python Flask simples):

# Estágio 1: build
FROM python:3.11-slim AS builder
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .

# Estágio 2: runtime (imagem final enxuta)
FROM python:3.11-alpine
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app .
EXPOSE 5000
CMD ["python", "main.py"]

Testes locais com Docker Compose:

# docker-compose.yml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=development

# Executar
docker-compose up --build
# Acessar http://localhost:5000

4. Configuração do Pipeline de Integração Contínua (CI)

Workflow do GitHub Actions (.github/workflows/ci-cd-pipeline.yml):

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/meu-app
  K8S_NAMESPACE: production

jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: pip install -r app/requirements.txt

      - name: Lint
        run: pip install flake8 && flake8 app/

      - name: Testes unitários
        run: cd app && python -m pytest test_main.py -v

      - name: Login no Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build e push da imagem
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.DOCKER_IMAGE }}:${{ github.sha }}

Gatilhos: push e pull request na branch main. A imagem é taggeada com o SHA do commit para rastreabilidade.


5. Configuração do Pipeline de Entrega Contínua (CD)

Manifestos Kubernetes no diretório k8s/:

deployment.yml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: meu-app
  namespace: production
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: meu-app
  template:
    metadata:
      labels:
        app: meu-app
    spec:
      containers:
      - name: app
        image: meuusuario/meu-app:latest
        ports:
        - containerPort: 5000
        readinessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 15
          periodSeconds: 20

service.yml:

apiVersion: v1
kind: Service
metadata:
  name: meu-app-service
  namespace: production
spec:
  selector:
    app: meu-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000
  type: LoadBalancer

Etapa de CD no workflow (após o push da imagem):

  cd:
    needs: ci
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configurar kubectl
        uses: azure/setup-kubectl@v4
        with:
          version: 'latest'

      - name: Configurar kubeconfig
        run: |
          echo "${{ secrets.KUBE_CONFIG }}" | base64 --decode > kubeconfig
          export KUBECONFIG=kubeconfig

      - name: Atualizar deployment
        run: |
          kubectl set image deployment/meu-app app=${{ env.DOCKER_IMAGE }}:${{ github.sha }} \
            --namespace=${{ env.K8S_NAMESPACE }}

A estratégia de rolling update com health checks garante zero downtime: o Kubernetes só substitui pods quando o readiness probe do novo pod responde com sucesso.


6. Gerenciamento de Segredos e Configurações Sensíveis

Secrets e ConfigMaps no Kubernetes:

# ConfigMap para variáveis não sensíveis
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  FLASK_ENV: "production"
  LOG_LEVEL: "info"

# Secret para credenciais
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: production
type: Opaque
data:
  DB_PASSWORD: c2VuaGEgY29tcGxleGE=  # base64

No deployment, injete os valores:

env:
  - name: FLASK_ENV
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: FLASK_ENV
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: app-secrets
        key: DB_PASSWORD

Boas práticas:
- Nunca armazene secrets no repositório; use GitHub Secrets para as variáveis do pipeline (ex.: DOCKER_PASSWORD, KUBE_CONFIG).
- Para ambientes mais robustos, integre com HashiCorp Vault ou sealed-secrets do Bitnami.


7. Monitoramento, Rollback e Validação do Pipeline

Health checks e readiness probes já definidos no deployment garantem que o tráfego só seja direcionado a pods saudáveis.

Estratégia de rollback automático:

# No workflow, adicione validação pós-deploy
- name: Validar deployment
  run: |
    kubectl rollout status deployment/meu-app --namespace=${{ env.K8S_NAMESPACE }} --timeout=120s

# Se falhar, rollback automático
- name: Rollback em caso de falha
  if: failure()
  run: |
    kubectl rollout undo deployment/meu-app --namespace=${{ env.K8S_NAMESPACE }}

Logs e métricas:

# Para logs centralizados
kubectl logs -l app=meu-app --namespace=production

# Prometheus + Grafana (instalação via Helm)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring

# Métricas customizadas da aplicação expostas em /metrics

8. Considerações Finais e Próximos Passos

Checklist de verificação:
- [ ] Pipeline CI executa lint, testes e build com sucesso
- [ ] Imagem Docker é enviada ao registry
- [ ] CD atualiza o deployment sem downtime
- [ ] Health checks e probes funcionam corretamente
- [ ] Rollback automático é acionado em falha
- [ ] Segredos são gerenciados via Secrets do K8s e GitHub Secrets

Extensões possíveis:
- GitOps com ArgoCD: o cluster sincroniza automaticamente com o repositório Git, eliminando a necessidade de kubectl set image no pipeline.
- Canary deployments: liberar a nova versão para 10% dos usuários antes do rollout completo, usando Service Mesh (Istio) ou Flagger.
- Cluster upgrades e multi-tenancy: temas avançados que se beneficiam deste pipeline como base sólida.

Este projeto final unifica Docker, Kubernetes e CI/CD em uma esteira automatizada, pronta para produção. A partir daqui, o céu (ou o cluster) é o limite.


Referências