PostgreSQL em produção com Docker
Rodar PostgreSQL em produção com Docker exige mais que um docker run com a imagem oficial. Você precisa garantir persistência de dados, healthcheck para dependências de startup, ajuste de memória para a VPS, logs estruturados e nunca expor o banco diretamente na internet. Este artigo cobre a configuração completa.
docker-compose.yml para produção
A configuração mínima recomendada para PostgreSQL em produção inclui volume nomeado, healthcheck, limites de recurso e reinício automático:
services:
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- pg_data:/var/lib/postgresql/data
- ./postgresql.conf:/etc/postgresql/postgresql.conf:ro
command: postgres -c config_file=/etc/postgresql/postgresql.conf
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 256M
networks:
- db_network
volumes:
pg_data:
networks:
db_network:
driver: bridgeTuning de memória (postgresql.conf)
O PostgreSQL usa os padrões conservadores da imagem oficial, adequados para ambientes de desenvolvimento. Para produção, ajuste conforme a RAM da VPS:
# postgresql.conf para VPS de 2 GB RAM dedicados ao banco
# Regras gerais:
# shared_buffers = 25% da RAM
# effective_cache_size = 75% da RAM
# work_mem = RAM / (max_connections * 2)
# Para VPS 2 GB:
shared_buffers = 512MB
effective_cache_size = 1536MB
maintenance_work_mem = 128MB
work_mem = 10MB
max_connections = 100
wal_buffers = 16MB
# Checkpoints (reduz I/O de pico)
checkpoint_completion_target = 0.9
checkpoint_timeout = 10min
# Paralelismo (para VPS com 2+ vCPUs)
max_parallel_workers_per_gather = 2
max_parallel_workers = 4
# Logs
log_min_duration_statement = 500
log_checkpoints = on
log_connections = off
log_lock_waits = onSegurança: nunca expor o banco na internet
O PostgreSQL deve ser acessível apenas dentro da rede Docker (pelo nome do serviço) ou via SSH tunnel. Nunca mapeie a porta 5432 em produção:
# CORRETO: sem mapeamento de porta (banco inacessível externamente)
services:
postgres:
image: postgres:16-alpine
# SEM "ports:" — acesso apenas pela rede Docker interna
networks:
- db_network
app:
environment:
DATABASE_URL: postgres://user:pass@postgres:5432/db
networks:
- db_network
# ERRADO para produção (expõe o banco na internet):
# ports:
# - "5432:5432"
# Para acesso externo seguro, use SSH tunnel:
ssh -L 5432:localhost:5432 root@IP_DA_VPS
# Depois conecte em localhost:5432 no seu DBeaver/pgAdmin localVerificar integridade e manutenção
Manutenção regular previne degradação de performance e corrupção silenciosa:
# VACUUM ANALYZE — limpar tuplas mortas e atualizar estatísticas
docker compose exec postgres psql -U postgres -d meu_banco \
-c "VACUUM ANALYZE;"
# VACUUM FULL — reescreve tabelas (requer lock, use em manutenção)
docker compose exec postgres psql -U postgres -d meu_banco \
-c "VACUUM FULL ANALYZE;"
# Ver tabelas com mais tuplas mortas (candidatas a VACUUM)
docker compose exec postgres psql -U postgres -d meu_banco -c "
SELECT schemaname, tablename, n_dead_tup, n_live_tup,
round(n_dead_tup::numeric/NULLIF(n_live_tup,0)*100, 2) AS dead_pct
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;"
# Verificar tamanho dos bancos
docker compose exec postgres psql -U postgres \
-c "SELECT pg_database.datname, pg_size_pretty(pg_database_size(pg_database.datname)) FROM pg_database ORDER BY pg_database_size(pg_database.datname) DESC;"Atualizar o PostgreSQL com zero downtime
Para atualizar a versão minor (16.1 → 16.5), basta puxar a nova imagem. Para major (15 → 16), é necessário pg_upgrade:
# Atualização minor (patch) — sem perda de dados
docker compose pull postgres
docker compose up -d postgres
# Verificar nova versão
docker compose exec postgres psql -U postgres -c "SELECT version();"
# Atualização major (ex: PG 15 → 16):
# 1. Fazer backup completo com pg_dumpall
docker compose exec postgres pg_dumpall -U postgres > backup-before-upgrade.sql
# 2. Parar o banco e remover o volume antigo
docker compose down
docker volume rm nome_do_projeto_pg_data
# 3. Mudar a tag da imagem no docker-compose.yml para postgres:16-alpine
# 4. Subir e restaurar
docker compose up -d postgres
cat backup-before-upgrade.sql | docker compose exec -T postgres psql -U postgres$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o PostgreSQL em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.