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



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."

BASH
# 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

100%
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: ⭐⭐)

YAML
# 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:
BASH
# 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: ⭐⭐⭐)

YAML
# 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:
YAML
# 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"
YAML
# 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
BASH
# 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: ⭐⭐)

BASH
# 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: ⭐⭐)

YAML
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

YAML
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

YAML
# ============================================
# 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:
YAML
# ============================================
# 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
BASH
# 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 -d Use 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 — --scale ou deploy.replicas? R: O argumento de linha de comando --scale tem precedência sobre a declaração YAML deploy.replicas. Se ambos forem definidos, o valor de --scale sobrescreve 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 --scale para 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 use service_healthy em ambientes de produção.

P: Como alterno entre variáveis em arquivos Compose em diferentes ambientes? R: ${VAR:-default} + arquivos .env. Coloque diferentes arquivos .env em cada ambiente: .env.dev / .env.prod. Especifique --env-file na 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


📝 Exercícios

  1. 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.
  2. Exercício Avançado (Dificuldade: ⭐⭐): Use --scale api=3 para escalar o serviço API para 3 réplicas e use docker compose ps para verificar.
  3. 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).
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%