DevOps

Docker Compose: Orquestrando Múltiplos Serviços Localmente Já leu

6 min de leitura

Docker Compose: Orquestrando Múltiplos Serviços Localmente
O artigo anterior terminou com um conjunto de comandos docker run que configurava manualmente rede, volumes e variáveis de ambiente para cada servi&

O artigo anterior terminou com um conjunto de comandos docker run que configurava manualmente rede, volumes e variáveis de ambiente para cada serviço. Esse processo funciona, mas não escala. Em um projeto real com cinco, dez ou quinze serviços, gerenciar tudo manualmente se torna impossível de manter, compartilhar e reproduzir.

O Docker Compose resolve isso com elegância: toda a definição do ambiente — serviços, redes, volumes, variáveis de ambiente, dependências entre serviços — vai em um único arquivo YAML chamado docker-compose.yml. O ambiente inteiro sobe com um comando, para com outro e pode ser compartilhado via Git com qualquer membro da equipe.


Estrutura do docker-compose.yml

A anatomia básica de um arquivo Compose:

services:        # define os containers que compõem o ambiente
  nome-servico:
    image: ...   # imagem base ou
    build: ...   # caminho para o Dockerfile
    ports: ...   # mapeamento de portas
    volumes: ... # montagem de volumes
    environment: # variáveis de ambiente
    networks: ... # redes às quais pertence
    depends_on: ... # dependências de outros serviços

volumes:         # volumes gerenciados pelo Docker
  nome-volume:

networks:        # redes customizadas
  nome-rede:

O Primeiro docker-compose.yml

Convertendo o ambiente do artigo anterior em um arquivo Compose:

# docker-compose.yml
services:
  postgres:
    image: postgres:16
    container_name: postgres
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: senha_segura
      POSTGRES_DB: minha_app
    volumes:
      - dados-postgres:/var/lib/postgresql/data
    networks:
      - rede-app
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d minha_app"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: redis
    command: redis-server --appendonly yes
    volumes:
      - dados-redis:/data
    networks:
      - rede-app
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

  api:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: api
    environment:
      NODE_ENV: production
      DATABASE_URL: postgresql://app:senha_segura@postgres:5432/minha_app
      REDIS_URL: redis://redis:6379
    ports:
      - "3000:3000"
    networks:
      - rede-app
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

volumes:
  dados-postgres:
  dados-redis:

networks:
  rede-app:
    driver: bridge

Comandos Essenciais do Docker Compose

# Sobe todos os serviços em segundo plano
docker compose up -d

# Sobe e reconstrói as imagens antes de subir
docker compose up -d --build

# Acompanha os logs de todos os serviços
docker compose logs -f

# Logs de um serviço específico
docker compose logs -f api

# Lista os serviços e seus estados
docker compose ps

# Para todos os serviços
docker compose stop

# Para e remove containers, redes e volumes anônimos
docker compose down

# Para, remove containers E volumes nomeados
docker compose down -v

# Executa um comando em um serviço em execução
docker compose exec api sh

# Escala um serviço para múltiplas instâncias
docker compose up -d --scale api=3

Variáveis de Ambiente com Arquivo .env

Colocar senhas diretamente no docker-compose.yml é uma má prática — o arquivo é versionado no Git. A solução é usar um arquivo .env na mesma pasta, que o Docker Compose carrega automaticamente:

# .env
POSTGRES_USER=app
POSTGRES_PASSWORD=senha_muito_segura
POSTGRES_DB=minha_app
NODE_ENV=production
APP_PORT=3000

O docker-compose.yml passa a referenciar as variáveis:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}

  api:
    build: .
    environment:
      NODE_ENV: ${NODE_ENV}
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
    ports:
      - "${APP_PORT}:3000"

O arquivo .env deve ser adicionado ao .gitignore. Em seu lugar, versiona-se um arquivo .env.example com as chaves necessárias mas sem valores reais — servindo como documentação para novos membros da equipe.


Profiles: Ativando Serviços Opcionais

O Docker Compose suporta profiles — grupos de serviços que só sobem quando explicitamente solicitados. Útil para ferramentas de desenvolvimento que não devem subir em produção:

services:
  api:
    build: .
    ports:
      - "3000:3000"

  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: senha123

  # Só sobe quando o profile 'dev' é ativado
  adminer:
    image: adminer
    profiles: [dev]
    ports:
      - "8080:8080"

  # Só sobe quando o profile 'monitoring' é ativado
  prometheus:
    image: prom/prometheus
    profiles: [monitoring]
    ports:
      - "9090:9090"
# Sobe apenas os serviços sem profile
docker compose up -d

# Sobe incluindo o profile de desenvolvimento
docker compose --profile dev up -d

# Sobe incluindo múltiplos profiles
docker compose --profile dev --profile monitoring up -d

Override Files: Configurações por Ambiente

O Docker Compose suporta múltiplos arquivos que são mesclados automaticamente. O padrão é usar docker-compose.yml como base e docker-compose.override.yml para sobrescrições locais de desenvolvimento:

# docker-compose.yml — configuração base (versionada)
services:
  api:
    build: .
    environment:
      NODE_ENV: production
    restart: unless-stopped
# docker-compose.override.yml — sobrescrições locais (no .gitignore)
services:
  api:
    environment:
      NODE_ENV: development
    volumes:
      - ./src:/app/src     # hot reload em desenvolvimento
    command: npm run dev

O Docker Compose mescla automaticamente os dois arquivos quando docker compose up é executado. Para produção, usa-se o arquivo base explicitamente:

docker compose -f docker-compose.yml up -d

Um Ambiente de Desenvolvimento Completo

Um exemplo realista que desenvolvedores de qualquer equipe podem usar imediatamente:

# docker-compose.yml
services:
  api:
    build:
      context: .
      target: development    # usa o estágio dev do multi-stage Dockerfile
    volumes:
      - ./src:/app/src
      - ./package.json:/app/package.json
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    command: npm run dev

  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-dev}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dev123}
      POSTGRES_DB: ${POSTGRES_DB:-devdb}
    volumes:
      - dados-postgres:/var/lib/postgresql/data
      - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dev}"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 3

  adminer:
    image: adminer
    profiles: [dev-tools]
    ports:
      - "8080:8080"
    depends_on:
      - postgres

volumes:
  dados-postgres:

networks:
  default:
    name: rede-dev

Com esse arquivo, qualquer desenvolvedor que clonar o repositório pode ter o ambiente completo rodando com:

cp .env.example .env
docker compose up -d

O Que Vem a Seguir

No próximo artigo serão abordadas as boas práticas para construção de imagens Docker — como reduzir tamanho, melhorar segurança e organizar Dockerfiles para ambientes de produção. É o artigo que transforma imagens funcionais em imagens prontas para o mundo real.


Referências para Aprofundamento

Documentação oficial - Docker Compose Documentation — docs.docker.com — Documentação completa do Docker Compose, incluindo referência de todas as opções do arquivo YAML. - Compose File Reference — docs.docker.com — Referência completa de todas as chaves disponíveis no arquivo docker-compose.yml.

Leitura técnica - Use Compose in Production — docs.docker.com — Guia oficial sobre considerações ao usar Docker Compose em ambientes de produção. - Environment Variables in Compose — docs.docker.com — Documentação detalhada sobre todas as formas de passar variáveis de ambiente no Compose.

Prática - Awesome Compose — GitHub — Repositório oficial do Docker com exemplos de docker-compose.yml para dezenas de stacks tecnológicas diferentes. Excelente referência para adaptar ao projeto em uso.

Comentários

Mais em DevOps

Permissões, Usuários e Grupos no Linux
Permissões, Usuários e Grupos no Linux

Em um servidor de produção, múltiplos serviços ro...

Estudar e realmente Aprender DevOps & Cloud
Estudar e realmente Aprender DevOps & Cloud

Existe um momento na carreira de todo desenvolvedor em que o código fu...

Processos, Serviços e o Comando `systemctl`
Processos, Serviços e o Comando `systemctl`

Cada programa em execução no Linux — seja um servidor web...