Docker: Orquestração Avançada com Compose
Última atualização: 2026-08-26
Desenvolvimento, teste e produção — um arquivo Compose gerencia os três ambientes.
1. O Que Você Vai Aprender
- Profiles: Configuração Multi-Ambiente
- Reutilização e Herança de Configuração (extends / override)
- Escalonamento horizontal
- Declaração de Limitações de Recursos
- Controle de Dependência com Verificação de Saúde
2. Uma História Real de uma Pessoa Líder Técnica
(1) Ponto de Dor: Três Ambientes, Três Arquivos de Configuração
Charlie precisa manter configurações Compose separadas para três ambientes: desenvolvimento, teste e produção. O ambiente de desenvolvimento requer hot reloading e ferramentas de depuração; o ambiente de teste requer uma stack completa de serviços; e o ambiente de produção requer limites de recursos e múltiplas réplicas. Os três arquivos YAML separados contêm muito código duplicado, então mudar algo em um arquivo significa mudar nos três.
(2) Solução com Profiles + Override
Charlie usou profiles e arquivos de override para implementar uma solução baseada em "uma configuração base + sobrescritas específicas do ambiente."
# Desenvolvimento: ativar perfil dev + sobrescritas dev
docker compose --profile dev -f docker-compose.yml -f docker-compose.dev.yml up -d
# Produção: apenas sobrescritas prod
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
(3) Resultado: 3 arquivos → 1 + 2 arquivos
De três arquivos completamente separados para um arquivo base mais dois arquivos de sobrescrita de diferenças. A configuração comum precisa ser mantida em apenas um lugar.
3. Profiles: Configuração Multi-Ambiente
(1) O Mecanismo de Profile
graph TB
BASE["docker-compose.yml<br/>Serviços base"] --> DEV["--profile dev<br/>+ ferramentas dev (hot-reload, adminer)"]
BASE --> TEST["--profile test<br/>+ executores de teste (selenium)"]
BASE --> PROD["--profile prod<br/>+ monitoramento (prometheus, grafana)"]
▶ Exemplo: --profile dev ativado (Dificuldade: ⭐⭐)
# docker-compose.yml com profiles
services:
api:
build: .
ports:
- "5000:5000"
environment:
- FLASK_ENV=development
db:
image: postgres:15-alpine
volumes:
- pg-data:/var/lib/postgresql/data
# Apenas dev: interface de gerenciamento de banco de dados
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
depends_on: [db]
# Apenas dev: hot-reload com depuração Flask
api-dev:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app
ports:
- "5000:5000"
- "5678:5678" # Porta de depuração
environment:
- FLASK_DEBUG=1
profiles: ["dev"]
# Apenas prod: monitoramento Prometheus
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
profiles: ["prod"]
volumes:
pg-data:
# Desenvolvimento: serviços base + perfil dev
docker compose --profile dev up -d
# Produção: serviços base + perfil prod
docker compose --profile prod up -d
# Apenas serviços base (sem perfil)
docker compose up -d
(1) Comparação entre Profiles e Override
| Dimensão | Profiles | Arquivos Override |
|---|---|---|
| Número de arquivos | 1 arquivo | 2–3 arquivos |
| Método de Ativação | --profile xxx |
-f base.yml -f override.yml |
| Cenários Adequados | Expansão de Serviços | Diferenças Significativas de Configuração |
| Componibilidade | Múltiplos perfis podem ser combinados | Sobrescrita em ordem |
4. Mesclagem de Arquivos Override
▶ Exemplo: Sobrescrevendo Configuração de Arquivo (Dificuldade: ⭐⭐⭐)
# docker-compose.yml (configuração base)
services:
api:
build: .
environment:
FLASK_ENV: production
restart: unless-stopped
db:
image: postgres:15-alpine
volumes:
- pg-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
pg-data:
# docker-compose.dev.yml (sobrescritas dev)
services:
api:
environment:
FLASK_ENV: development
FLASK_DEBUG: "1"
volumes:
- ./src:/app # Hot-reload: montar código fonte
ports:
- "5678:5678" # Porta de depuração
# Serviço apenas para dev
adminer:
image: adminer
ports:
- "8081:8080"
# docker-compose.prod.yml (sobrescritas prod)
services:
api:
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
retries: 3
# Apenas prod: proxy reverso Nginx
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.prod.conf:/etc/nginx/conf.d/default.conf
depends_on:
- api
# Desenvolvimento
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# Produção
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Pré-visualizar configuração mesclada (dry-run)
docker compose -f docker-compose.yml -f docker-compose.prod.yml config
5. Escalonamento Horizontal
▶ Exemplo: Extensão --scale (Dificuldade: ⭐⭐)
# Escalar o serviço API para 3 réplicas
docker compose up -d --scale api=3
# Escalar dinamicamente em uma stack em execução
docker compose up -d --scale api=5
(1) Considerações sobre Escalonamento
| Problema | Causa | Solução |
|---|---|---|
| Conflito de Porta | Múltiplas réplicas mapeadas para a mesma porta do host | Apenas um ponto de entrada exposto (Nginx); a API não mapeia para uma porta do host |
| Consistência de Dados | Escrita em várias cópias no mesmo armazenamento | Apenas serviços sem estado são adequados para escalonamento; bancos de dados compartilhados |
| Balanceamento de Carga | Como as requisições são distribuídas entre várias réplicas | Nginx upstream ou round-robin DNS integrado do Docker |
▶ Exemplo: Escalonamento declarativo com deploy.replicas (Dificuldade: ⭐⭐)
services:
api:
build: .
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 256M
reservations:
cpus: "0.25"
memory: 128M
# NÃO mapear portas para serviços escalados
# ports: ["5000:5000"] ← Isso quebra com replicas > 1
nginx:
image: nginx:alpine
ports:
- "80:80"
# O upstream do Nginx usa DNS round-robin para api:5000
6. Limitações de Recursos
(1) Configuração de deploy.resources
services:
api:
deploy:
resources:
limits: # Limites rígidos (elimina se excedido)
cpus: "1.0"
memory: 512M
reservations: # Garantias flexíveis (mínimo)
cpus: "0.5"
memory: 256M
| Campo | Propósito | Efeito |
|---|---|---|
limits.cpus |
Limite de CPU | Excedido: Limitado |
limits.memory |
Limite de Memória | Excedido: OOM Kill |
reservations.cpus |
Garantia Mínima de CPU | Garantia de Agendamento |
reservations.memory |
Garantia Mínima de Memória | Garantia de Agendamento |
7. Exemplo Completo: Projeto Compose para Três Ambientes
# ============================================
# docker-compose.yml - Configuração base
# ============================================
services:
api:
build:
context: .
dockerfile: Dockerfile
environment:
DATABASE_URL: postgresql://postgres:${DB_PASSWORD:-secret}@db:5432/${DB_NAME:-myapp}
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
- backend
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
POSTGRES_DB: ${DB_NAME:-myapp}
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- backend
# Apenas dev: Interface Adminer DB
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
networks:
- backend
volumes:
pg-data:
networks:
backend:
# ============================================
# docker-compose.prod.yml - Sobrescritas de produção
# ============================================
services:
api:
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 5s
retries: 3
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.prod.conf:/etc/nginx/conf.d/default.conf
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- backend
# Desenvolvimento
docker compose --profile dev up -d
# Produção (3 réplicas + Nginx + limites de recursos)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Verificar escalonamento
docker compose -f docker-compose.yml -f docker-compose.prod.yml ps
❓ Perguntas Frequentes
P: Profiles e arquivos override podem ser usados juntos? R: Sim.
docker compose --profile dev -f docker-compose.yml -f docker-compose.dev.yml up -dUse profiles e arquivos override juntos. Profiles gerenciam a adição e remoção de serviços, enquanto arquivos override gerenciam diferenças de configuração; os dois se complementam.
P: Qual tem precedência —
--scaleoudeploy.replicas? R: O argumento de linha de comando--scaletem precedência sobre a declaração YAMLdeploy.replicas. Se ambos forem definidos, o valor de--scalesobrescreve o valor no YAML. Em um ambiente de produção, recomendamos usar a declaração YAML (que oferece suporte ao controle de versão); use--scalepara ajustes rápidos durante a depuração.
P: Como controlo a ordem em que os serviços iniciam? R:
depends_on+condition. Três condições: ①service_started(padrão; aguarda apenas a inicialização); ②service_healthy(aguarda a verificação de saúde ser aprovada); ③service_completed_successfully(aguarda a conclusão das tarefas de inicialização). Sempre useservice_healthyem ambientes de produção.
P: Como alterno entre variáveis em arquivos Compose em diferentes ambientes? R:
${VAR:-default}+ arquivos.env. Coloque diferentes arquivos.envem cada ambiente:.env.dev/.env.prod. Especifique--env-filena inicialização:docker compose --env-file .env.prod up -d.
P: Como as portas são tratadas quando há múltiplas réplicas? R: O serviço escalado não pode mapear portas do host (múltiplas réplicas causariam conflitos). Permita apenas que o Nginx/HAProxy mapeie portas; o serviço API se comunica internamente pela rede. O upstream do Nginx usa DNS round-robin do Docker para distribuir automaticamente o tráfego entre várias réplicas.
📖 Resumo
- Profiles: Adicionar ou remover serviços no mesmo arquivo com base no ambiente;
--profile devpara ativar - Arquivo override:
-f base.yml -f override.ymlConfiguração mesclada, adequada para um grande número de diferenças - Escalonamento:
--scale api=3oudeploy.replicas: 3Escalonamento Horizontal de Serviços Sem Estado - O serviço estendido não pode mapear para uma porta do host — use um ponto de entrada Nginx + round-robin DNS interno
deploy.resourcesDeclarando Limites e Reservas de CPU/Memóriadepends_on: { condition: service_healthy }Garante que as dependências estejam realmente prontas
📝 Exercícios
- Exercício Básico (Dificuldade: ⭐): Escreva dois conjuntos de arquivos override (um para dev e um para prod) para a aplicação da Aula 12; adicione hot reloading para dev e limites de recursos para prod.
- Exercício Avançado (Dificuldade: ⭐⭐): Use
--scale api=3para escalar o serviço API para 3 réplicas e usedocker compose pspara verificar. - Desafio (Dificuldade: ⭐⭐⭐): Configure um proxy reverso Nginx para uma API com 3 réplicas e verifique se as requisições são distribuídas para diferentes réplicas (verificando os logs de diferentes contêineres).