Template base para produção
Estrutura mínima de um serviço de produção com todas as configurações essenciais:
services:
app:
image: minha-app:1.2.3 # versão fixa, nunca :latest em prod
restart: always
env_file: .env # variáveis sensíveis fora do compose
ports:
- "127.0.0.1:3000:3000" # bind apenas no localhost, NGINX expõe externamente
depends_on:
db:
condition: service_healthy # aguarda o banco estar pronto
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
db:
image: postgres:16
restart: always
env_file: .env
volumes:
- pg_data:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 1G
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_data:restart: always vs unless-stopped
Escolha a política de restart correta para cada tipo de serviço:
Arquivo .env e segredos
Variáveis sensíveis (senhas, API keys) nunca devem aparecer no docker-compose.yml, use arquivo .env:
# .env (nunca commite no git — adicione ao .gitignore)
POSTGRES_USER=appuser
POSTGRES_PASSWORD=senha_super_segura_aqui
POSTGRES_DB=producao
SECRET_KEY=chave_jwt_256_bits_aqui
# No docker-compose.yml, referencie:
# env_file: .env
# Ou por variável individual:
# environment:
# POSTGRES_USER: ${POSTGRES_USER}
# Verificar quais variáveis estão sendo resolvidas:
docker compose configVersões fixas de imagem em produção
Nunca use :latest em produção, uma atualização automática pode quebrar seu serviço silenciosamente:
# Ruim — :latest pode mudar a qualquer momento
image: postgres:latest
# Bom — versão major/minor fixa, patch automático
image: postgres:16
# Melhor — versão completamente fixa com digest (imutável)
image: postgres:16.3Estratégia de deploy sem downtime
Para deploys com downtime mínimo usando Compose puro (sem Swarm/Kubernetes):
# Pull da nova imagem enquanto a versão atual ainda está rodando
docker compose pull app
# Recria apenas o serviço atualizado (outros serviços continuam)
docker compose up -d --no-deps app
# Verificar se o healthcheck passou antes de considerar o deploy OK
docker compose ps
docker inspect app_container_1 | grep -A5 '"Health"'