Compose avançado: profiles e overrides
Nem todo serviço precisa subir sempre, e dev/produção não deviam compartilhar o mesmo arquivo sem ajuste nenhum.
Até aqui, um único docker-compose.yml serviu tanto pra rodar localmente quanto (com variável de ambiente trocada) pra produção. Isso funciona pra projetos simples, mas dois problemas aparecem rápido: você quer coisas em dev que não fazem sentido em produção (bind mount de código, porta de debug), e às vezes só quer subir parte dos serviços, não todos. O Compose tem mecanismos prontos pra isso.
docker-compose.override.yml — o Compose já espera por ele
Se existir um arquivo chamado exatamente docker-compose.override.yml na mesma pasta do docker-compose.yml, o Compose mescla os dois automaticamente ao rodar docker compose up — sem precisar passar -f nenhum. É o lugar natural pra ajustes só de desenvolvimento local, mantendo o arquivo principal mais "neutro".
services:
api:
build: .
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/app
db:
image: postgres:16-alpineservices:
api:
volumes:
- .:/app # bind mount pra hot-reload em dev
ports:
- "9229:9229" # porta de debug do Node, só faz sentido localmenteMúltiplos -f — combinando arquivos explicitamente
Pra produção, você não quer o override de dev, mas quer um arquivo próprio com ajustes de produção. Nesse caso, ignore o mecanismo automático e escolha os arquivos na mão, na ordem que fizer sentido — o Compose aplica um por cima do outro, na ordem em que aparecem:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dComo o override automático só é aplicado quando você não passa -f, usar -f explicitamente (como acima) já ignora o docker-compose.override.yml por padrão — é assim que dev e produção deixam de compartilhar ajustes que só fazem sentido num dos dois lados.
profiles — subir só parte dos serviços
Serviços auxiliares (uma interface de administração de banco, uma ferramenta de debug) nem sempre precisam subir junto com o resto. Marcando um serviço com profiles, ele só sobe quando esse profile é ativado explicitamente — por padrão, fica de fora.
services:
api:
build: .
# sem "profiles" — sobe sempre
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["debug"] # só sobe se o profile "debug" for ativadodocker compose up -d # sobe só "api" (e "db", se não tiver profile)
docker compose --profile debug up -d # sobe "api", "db" E "adminer"Variáveis por ambiente: dev vs prod no mesmo projeto
services:
api:
restart: unless-stopped
env_file: .env.production
# sem bind mount, sem porta de debug — só o necessário pra rodar a imagem já buildadaA combinação docker-compose.yml (base) + docker-compose.override.yml (dev, automático) ou + docker-compose.prod.yml (produção, explícito via -f) evita duplicar o arquivo inteiro pra cada ambiente — só o que muda de fato fica declarado separadamente.
Exercício
Um projeto tem docker-compose.yml com os serviços api e db, e precisa de um serviço mailhog (captura de e-mail pra teste) que só deveria subir em desenvolvimento, nunca em produção. Onde declarar mailhog, e como isso evita que ele suba sem querer em produção?