CI/CD - Continuous Integration & Continuous Deployment¶
O que é CI/CD?¶
CI/CD é uma metodologia de desenvolvimento que combina Continuous Integration (CI) e Continuous Deployment/Delivery (CD) para automatizar o processo de desenvolvimento, teste e deployment de software.
Continuous Integration (CI)¶
Integração Contínua é a prática de integrar código frequentemente ao repositório principal, onde cada integração é verificada por builds automáticos e testes.
Benefícios: - ✅ Detecção precoce de bugs - ✅ Redução de conflitos de merge - ✅ Feedback rápido para desenvolvedores - ✅ Melhoria na qualidade do código
Continuous Deployment/Delivery (CD)¶
Continuous Delivery: Código sempre pronto para produção, mas deployment manual Continuous Deployment: Deployment automático em produção após passar por todos os testes
Benefícios: - ✅ Releases mais frequentes e confiáveis - ✅ Redução de riscos de deployment - ✅ Time-to-market mais rápido - ✅ Rollbacks automáticos
Pipeline CI/CD¶
Um pipeline CI/CD típico inclui as seguintes etapas:
graph LR
A[Code Push] --> B[Build]
B --> C[Unit Tests]
C --> D[Integration Tests]
D --> E[Security Scan]
E --> F[Deploy Staging]
F --> G[E2E Tests]
G --> H[Deploy Production] Etapas do Pipeline¶
- Source/Trigger - Push de código ou merge request
- Build - Compilação e criação de artefatos
- Test - Execução de testes automatizados
- Security - Análise de vulnerabilidades
- Package - Criação de imagens Docker ou pacotes
- Deploy - Deployment em ambientes
- Monitor - Monitoramento pós-deployment
Principais Tecnologias CI/CD¶
Plataformas de CI/CD¶
GitLab CI/CD¶
- ✅ Integrado ao GitLab
- ✅ Runners próprios ou compartilhados
- ✅ Arquivo
.gitlab-ci.yml - ✅ Docker Registry integrado
GitHub Actions¶
- ✅ Integrado ao GitHub
- ✅ Marketplace de actions
- ✅ Workflows em YAML
- ✅ Runners gratuitos e self-hosted
Jenkins¶
- ✅ Open source e extensível
- ✅ Plugins abundantes
- ✅ Pipeline as Code (Jenkinsfile)
- ✅ Distribuído
Azure DevOps¶
- ✅ Ecossistema Microsoft
- ✅ Azure Pipelines
- ✅ Integração com Azure
- ✅ Agentes próprios ou Microsoft
CircleCI¶
- ✅ Cloud-native
- ✅ Configuração YAML
- ✅ Docker-first
- ✅ Orbs (pacotes reutilizáveis)
Ferramentas Complementares¶
Controle de Versão¶
- Git - Controle de versão distribuído
- GitFlow - Modelo de branching
- Semantic Versioning - Versionamento semântico
Testes¶
- Jest/Mocha - Testes JavaScript
- JUnit - Testes Java
- PyTest - Testes Python
- Selenium - Testes E2E
- SonarQube - Qualidade de código
Containerização¶
- Docker - Containerização
- Kubernetes - Orquestração
- Helm - Gerenciamento de deployments K8s
Monitoramento¶
- Prometheus - Métricas
- Grafana - Dashboards
- ELK Stack - Logs
- Sentry - Error tracking
CI/CD com GitLab - Passo a Passo¶
1. Configuração Inicial¶
Estrutura do Projeto¶
projeto/
├── .gitlab-ci.yml # Configuração CI/CD
├── Dockerfile # Imagem Docker
├── docker-compose.yml # Desenvolvimento local
├── k8s/ # Manifests Kubernetes
│ ├── deployment.yaml
│ └── service.yaml
└── src/ # Código fonte
2. Arquivo .gitlab-ci.yml Básico¶
# Definir stages do pipeline
stages:
- build
- test
- security
- package
- deploy
# Variáveis globais
variables:
DOCKER_REGISTRY: registry.gitlab.com
IMAGE_NAME: $CI_REGISTRY_IMAGE
DOCKER_DRIVER: overlay2
# Configurações globais
before_script:
- echo "Starting pipeline for $CI_COMMIT_REF_NAME"
# Stage: Build
build:
stage: build
image: node:18-alpine
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
only:
- main
- develop
- merge_requests
3. Pipeline Completo para Aplicação Node.js¶
stages:
- build
- test
- security
- package
- deploy-staging
- deploy-production
variables:
NODE_VERSION: "18"
DOCKER_REGISTRY: $CI_REGISTRY
IMAGE_NAME: $CI_REGISTRY_IMAGE
STAGING_URL: https://app-staging.exemplo.com
PRODUCTION_URL: https://app.exemplo.com
# Cache para node_modules
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
# Build da aplicação
build:
stage: build
image: node:${NODE_VERSION}-alpine
script:
- npm ci
- npm run build
- echo "Build completed successfully"
artifacts:
paths:
- dist/
- node_modules/
expire_in: 1 hour
only:
- main
- develop
- merge_requests
# Testes unitários
test:unit:
stage: test
image: node:${NODE_VERSION}-alpine
script:
- npm run test:unit
- npm run test:coverage
coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
paths:
- coverage/
only:
- main
- develop
- merge_requests
# Testes de integração
test:integration:
stage: test
image: node:${NODE_VERSION}-alpine
services:
- postgres:13
- redis:6-alpine
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_pass
DATABASE_URL: postgresql://test_user:test_pass@postgres:5432/test_db
script:
- npm run test:integration
only:
- main
- develop
# Análise de segurança com SAST
security:sast:
stage: security
image: node:${NODE_VERSION}-alpine
script:
- npm audit --audit-level high
- npx retire --severity medium
allow_failure: true
only:
- main
- develop
# Build da imagem Docker
package:
stage: package
image: docker:20.10.16
services:
- docker:20.10.16-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
- docker build -t $IMAGE_NAME:latest .
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
- docker push $IMAGE_NAME:latest
only:
- main
- develop
# Deploy em staging
deploy:staging:
stage: deploy-staging
image: alpine/helm:latest
environment:
name: staging
url: $STAGING_URL
script:
- apk add --no-cache curl
- helm upgrade --install app-staging ./k8s/helm-chart
--set image.tag=$CI_COMMIT_SHA
--set ingress.host=$STAGING_URL
--namespace staging
--create-namespace
only:
- develop
# Deploy em produção (manual)
deploy:production:
stage: deploy-production
image: alpine/helm:latest
environment:
name: production
url: $PRODUCTION_URL
script:
- helm upgrade --install app-prod ./k8s/helm-chart
--set image.tag=$CI_COMMIT_SHA
--set ingress.host=$PRODUCTION_URL
--namespace production
--create-namespace
when: manual
only:
- main
4. Configurações Avançadas¶
Multi-environment com Review Apps¶
# Review apps para merge requests
review:
stage: deploy
image: alpine/helm:latest
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://$CI_COMMIT_REF_SLUG.review.exemplo.com
on_stop: stop_review
script:
- helm upgrade --install review-$CI_COMMIT_REF_SLUG ./k8s/helm-chart
--set image.tag=$CI_COMMIT_SHA
--set ingress.host=$CI_COMMIT_REF_SLUG.review.exemplo.com
--namespace review
only:
- merge_requests
# Parar review app
stop_review:
stage: deploy
image: alpine/helm:latest
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
script:
- helm uninstall review-$CI_COMMIT_REF_SLUG --namespace review
when: manual
only:
- merge_requests
Deploy com Blue-Green¶
deploy:blue-green:
stage: deploy
image: kubectl:latest
script:
# Deploy na versão blue
- kubectl set image deployment/app-blue app=$IMAGE_NAME:$CI_COMMIT_SHA
- kubectl rollout status deployment/app-blue
# Testes de smoke
- curl -f http://blue.exemplo.com/health
# Switch do tráfego
- kubectl patch service app-service -p '{"spec":{"selector":{"version":"blue"}}}'
# Aguardar e verificar
- sleep 30
- curl -f http://app.exemplo.com/health
when: manual
only:
- main
5. GitLab Runner Configuration¶
Configurar GitLab Runner (Self-hosted)¶
# Instalar GitLab Runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner
# Registrar runner
sudo gitlab-runner register \
--url "https://gitlab.com/" \
--registration-token "YOUR_TOKEN" \
--executor "docker" \
--docker-image "alpine:latest" \
--description "docker-runner" \
--tag-list "docker,aws" \
--run-untagged="true" \
--locked="false" \
--access-level="not_protected"
Runner com Docker-in-Docker¶
# /etc/gitlab-runner/config.toml
[[runners]]
name = "docker-runner"
url = "https://gitlab.com/"
token = "YOUR_TOKEN"
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:20.10.16"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
shm_size = 0
6. Boas Práticas CI/CD¶
Segurança¶
# Usar secrets do GitLab
variables:
DATABASE_URL: $DATABASE_URL # Variável protegida
API_KEY: $API_KEY # Variável mascarada
# Scan de vulnerabilidades
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
Performance¶
# Cache inteligente
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
# Paralelização de jobs
test:
parallel: 3
script:
- npm run test -- --testPathPattern=$((CI_NODE_INDEX-1))
Monitoramento¶
# Notificações Slack
notify:slack:
stage: .post
image: alpine:latest
script:
- apk add --no-cache curl
- |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Deploy completed: '$PRODUCTION_URL'"}' \
$SLACK_WEBHOOK_URL
when: on_success
only:
- main
7. Exemplo com Múltiplos Ambientes¶
# Configuração por ambiente
.deploy_template: &deploy_template
image: alpine/helm:latest
script:
- helm upgrade --install $APP_NAME ./k8s/helm-chart
--set image.tag=$CI_COMMIT_SHA
--set ingress.host=$APP_URL
--set resources.limits.memory=$MEMORY_LIMIT
--namespace $NAMESPACE
--create-namespace
deploy:development:
<<: *deploy_template
stage: deploy
environment:
name: development
url: https://app-dev.exemplo.com
variables:
APP_NAME: app-dev
APP_URL: app-dev.exemplo.com
NAMESPACE: development
MEMORY_LIMIT: 512Mi
only:
- develop
deploy:staging:
<<: *deploy_template
stage: deploy
environment:
name: staging
url: https://app-staging.exemplo.com
variables:
APP_NAME: app-staging
APP_URL: app-staging.exemplo.com
NAMESPACE: staging
MEMORY_LIMIT: 1Gi
only:
- main
deploy:production:
<<: *deploy_template
stage: deploy
environment:
name: production
url: https://app.exemplo.com
variables:
APP_NAME: app-prod
APP_URL: app.exemplo.com
NAMESPACE: production
MEMORY_LIMIT: 2Gi
when: manual
only:
- main
Troubleshooting Comum¶
Problemas Frequentes¶
-
Build falha por dependências
-
Testes flaky
-
Deploy timeout