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.