↓Pular para o conteúdo principal
  1. blog/
ARTIGO TÉCNICO

O antipattern do docker compose down -v: runbook de mudança segura num n8n com estado

Checklist de alteração em produção pra um n8n em modo fila (Postgres + Redis + worker) — o maior risco operacional não é recriar containers, é remover volume sem querer.

·3 minutos

A tese #

Alterar um stack Docker com estado em produção (n8n em modo fila, Postgres, Redis, worker separado) não é arriscado por causa do comando que recria os containers. É arriscado por causa do comando vizinho, que parece inofensivo e apaga tudo:

1
2
3
4
5
# faz o que parece: recria containers, preserva volume
docker compose --env-file .env up -d --force-recreate

# faz o que ninguém quer: apaga os volumes nomeados junto
docker compose down -v

A regra número um do runbook não é sobre performance nem sobre configuração — é nunca rodar down -v, nunca docker volume rm, nunca trocar nome de volume no compose sem migração planejada.


Antes de tocar em qualquer coisa #

1
docker compose --env-file .env config > /tmp/rendered.yml

Renderiza o compose com as variáveis já interpoladas e confere se os serviços esperados (n8n, n8n-worker, postgres, redis), os depends_on: service_healthy e os healthchecks estão realmente lá — antes de qualquer coisa subir, não depois.

Depois, identificar os nomes reais dos volumes no host, não os que “deveriam ser” pelo nome do projeto:

1
docker volume ls | grep -E 'n8n|postgres|redis'

Um volume com nome levemente diferente do esperado é o motivo mais comum de alguém rodar um docker volume rm no volume errado.


Backup obrigatório, sem exceção #

1
docker exec -t n8n_postgres pg_dump -U n8n -d n8n > backup/n8n_$(date +%F_%H%M%S).sql

E, se houver espaço, backup físico do volume também — dump lógico cobre corrupção de dado, backup físico cobre problema de volume/filesystem:

1
2
3
4
docker run --rm \
  -v <volume_postgres_real>:/from \
  -v "$(pwd)/backup:/to" \
  alpine sh -c "cd /from && tar czf /to/postgres_$(date +%F_%H%M%S).tar.gz ."

Só depois de confirmar que o arquivo existe e não está vazio (du -h) é que a mudança pode prosseguir.


O que validar nos primeiros minutos #

Não é só “os containers subiram”. Grep específico no log procurando os sintomas que realmente indicam problema:

Database connection timed out
Database connection recovered
Offer expired
ECONNREFUSED
too many clients
remaining connection slots are reserved
OOM / Killed

E teste de conectividade direto de dentro do container do n8n pro Postgres e pro Redis, sem depender só do log dizer que está tudo bem:

1
2
3
4
docker exec -it n8n node -e \
  "const net=require('net');const s=net.connect(5432,'postgres');
   s.on('connect',()=>{console.log('db ok');process.exit(0)});
   s.on('error',e=>{console.error(e.message);process.exit(1)})"

Rollback não é restaurar backup #

Rollback, nesse runbook, significa voltar pro compose/env anterior e recriar containers — os volumes continuam intocados o tempo todo. Restaurar o dump do Postgres é o último recurso, usado só se houver incidente real de corrupção de dado, com confirmação explícita antes de rodar. Misturar os dois conceitos é o jeito mais fácil de perder dado que não precisava ter sido perdido.


Monitorar depois não é opcional #

24 horas observando frequência de timeout de conexão, uso de memória e disco do host, contagem de conexões ativas no Postgres. Se o host já estiver apertado de memória ou disco, isso sozinho pode continuar causando os mesmos sintomas mesmo com o compose corrigido — o runbook existe pra mudança de configuração, não substitui capacidade insuficiente de host.


Tecnologias #

Docker Compose · n8n (modo fila) · PostgreSQL · Redis

TEM UM CENÁRIO PARECIDO?

Me chama.

Manda o contexto, os sintomas e o que já foi testado. Bora organizar as evidências antes de sair mexendo.

Falar com Castro →
Sem enrolação. Com evidência.