Pipeline de CI: build, testes e lint automatizados
1. Fundamentos de uma Pipeline de CI para Containers
Uma pipeline de CI (Continuous Integration) é a espinha dorsal de qualquer estratégia DevOps moderna. Ela automatiza a integração de código, executando build, testes e verificações de qualidade sempre que um desenvolvedor faz push para o repositório. No contexto de Docker e Kubernetes, a CI ganha ainda mais relevância: ela garante que cada alteração produza uma imagem de container confiável, testada e segura antes de chegar ao cluster.
A principal diferença entre CI e CD é clara: CI foca na integração contínua do código e validação automatizada, enquanto CD (Continuous Delivery/Deployment) trata da entrega ou deploy automático para produção. Neste artigo, focamos exclusivamente na fase de CI, que prepara o terreno para uma CD eficiente.
2. Estrutura do Projeto e Preparação do Repositório
Para uma pipeline de CI eficaz, a organização do repositório é fundamental. Considere a seguinte estrutura:
meu-projeto/
├── src/
│ └── app.py
├── tests/
│ ├── test_unit.py
│ └── test_integration.py
├── Dockerfile
├── .hadolint.yaml
├── requirements.txt
└── .github/
└── workflows/
└── ci.yml
Adotar uma branch strategy como Trunk-based Development ou Git Flow simplifica o versionamento. No Trunk-based, todas as alterações são integradas na branch principal (main), com releases a partir de tags. Para este artigo, usaremos GitHub Actions como orquestrador da pipeline.
3. Etapa de Lint e Verificação de Qualidade de Código
A etapa de lint é a primeira barreira de qualidade. Ela deve falhar rapidamente para evitar desperdício de recursos.
Exemplo de lint com Hadolint (Dockerfile) e Pylint (código Python):
- name: Lint Dockerfile
run: |
docker run --rm -v $(pwd):/code hadolint/hadolint:latest \
hadolint /code/Dockerfile
- name: Lint Python code
run: |
pip install pylint
pylint src/ --fail-under=8.0
Essas verificações garantem boas práticas de segurança (como não expor portas desnecessárias) e formatação consistente. Se o lint falhar, a pipeline deve ser interrompida imediatamente, economizando minutos preciosos.
4. Etapa de Build da Imagem Docker
O build da imagem Docker deve ser otimizado com cache de camadas e Docker BuildKit.
Exemplo de build com cache e tagging semântico:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and tag image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: false
tags: |
myapp:latest
myapp:${{ github.sha }}
myapp:${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max
O uso de docker/build-push-action com cache do GitHub Actions (type=gha) acelera builds subsequentes em até 70%. O tagging semântico com latest, SHA do commit e nome da branch facilita a rastreabilidade.
5. Etapa de Testes Automatizados
Testes automatizados dentro do container garantem que o ambiente de execução seja idêntico ao de produção.
Exemplo de testes unitários com pytest:
- name: Run unit tests
run: |
docker build -t myapp:test --target=test .
docker run --rm myapp:test pytest tests/test_unit.py -v
Para testes de integração com banco de dados, use docker-compose para subir dependências:
- name: Integration tests
run: |
docker-compose -f docker-compose.test.yml up -d db
docker build -t myapp:integration .
docker run --rm --network=test_net myapp:integration \
pytest tests/test_integration.py -v
docker-compose down
A validação de saúde da imagem pode ser feita com um healthcheck no Dockerfile e verificação pós-build:
FROM python:3.11-slim AS final
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1
6. Scaneamento de Segurança e Vulnerabilidades
A segurança não é opcional. Ferramentas como Trivy escaneiam a imagem contra bancos de dados de vulnerabilidades conhecidas.
Exemplo de scan com Trivy:
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
Se uma vulnerabilidade crítica for encontrada, a pipeline falha. Para dependências Python, adicione pip-audit:
- name: Audit Python dependencies
run: |
pip install pip-audit
pip-audit --requirement requirements.txt --desc
7. Publicação da Imagem no Registry
Após validação, publique a imagem em um registry como GitHub Container Registry (GHCR) ou Docker Hub.
Exemplo de push autenticado para GHCR:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
Use tags imutáveis (SHA do commit) para garantir rastreabilidade. Evite sobrescrever tags comuns como latest sem validação.
8. Integração com Kubernetes (K8s) e Próximos Passos
Com a imagem publicada, o próximo passo é gerar manifestos YAML para deploy no Kubernetes. Ferramentas como Kustomize ou Helm facilitam a parametrização.
Exemplo de atualização de deployment via Kustomize:
- name: Update K8s manifest
run: |
cd k8s/overlays/production
kustomize edit set image myapp=ghcr.io/${{ github.repository }}:${{ github.sha }}
git commit -m "Update image tag to ${{ github.sha }}"
git push
Isso pode disparar uma pipeline de CD (usando ArgoCD ou Flux) para aplicar as mudanças no cluster. Notificações pós-CI via Slack ou e-mail mantêm a equipe informada:
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Pipeline de CI concluída para ${{ github.repository }}@${{ github.sha }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Conclusão
Uma pipeline de CI bem estruturada para Docker e Kubernetes não apenas automatiza builds e testes, mas também incorpora lint, segurança e validação de qualidade desde o primeiro commit. Ao seguir este roteiro, você garante que cada imagem publicada seja confiável, segura e pronta para deploy, reduzindo riscos e acelerando o ciclo de desenvolvimento.
Referências
- GitHub Actions Documentation - Building and testing Docker images — Guia oficial do GitHub para build e teste de imagens Docker em pipelines CI.
- Hadolint - Dockerfile Linter — Ferramenta de lint para Dockerfile que verifica boas práticas e segurança.
- Trivy - Vulnerability Scanner for Containers — Scanner de vulnerabilidades open-source para imagens Docker, suportado por GitHub Actions.
- Pytest Documentation — Framework de testes Python amplamente utilizado em pipelines CI para testes unitários e de integração.
- Kustomize - Kubernetes Native Configuration Management — Ferramenta para gerenciar manifestos Kubernetes de forma declarativa, ideal para CI/CD.
- Docker BuildKit - Build Performance and Security — Documentação oficial sobre BuildKit para builds Docker mais rápidos e seguros.