Reformatei a última réplica do meu banco numa "migração simples" de disco
Ontem eu quase perdi um banco de dados inteiro. A culpa foi minha, e a sequência de erros é boa demais pra não compartilhar.
Contexto rápido: rodo um cluster Kubernetes localmente (k3s), com Longhorn cuidando do storage. Um node morreu (o SSD do sistema parou de aceitar escrita) e eu acabei precisando trocar. Aproveitei pra consolidar o storage: jogar os HDDs grandes todos num nó só e deixar os outros dois rodando só em NVMe. Plano de 20 minutos. No papel.
Não foi um erro isolado! Foram quatro, em fila, cada um destravando o próximo:
flowchart TD
P["Migração de storage<br/>(mover HDDs pra 1 nó)"]
P --> A1["#1 fstab monta por /dev/sdb,<br/>não por UUID"]
A1 --> A2["Reboot reordena os devices"]
A2 --> A3["Discos montam TROCADOS<br/>Longhorn: DiskFilesystemChanged"]
P --> B1["#2 Não confirmei qual<br/>máquina física era qual"]
B1 --> B2["Desliguei e abri o nó ERRADO"]
B2 --> C1["#3 mkfs no disco que saiu"]
C1 --> C2{"#4 Chequei se algum volume<br/>tinha a última cópia ali?"}
C2 -->|"'0 faulted', achei seguro"| BOOM["Ultima replica viva<br/>de um banco apagada"]
BOOM --> S1["Backup pg_dump das 06h"]
BOOM --> S2["Humano: 'valida antes de promover'"]
S1 --> R["Restore + cluster recuperado"]
S2 --> R
Erro 1, fstab por device. Meu /etc/fstab montava os discos por /dev/sdb, /dev/sdc, o nome que o kernel dá na ordem que ele acha os discos. Reiniciei a máquina e o kernel enumerou numa ordem diferente. Cada disco montou no lugar do outro. O Longhorn olhou, viu que o disco no caminho esperado não era o que ele tinha registrado, e marcou tudo como "filesystem changed". Vários volumes degradados de uma vez, do nada.
Erro 2, máquina errada. O rótulo que eu tinha na cabeça não batia com o hostname que o cluster usava. Desliguei e abri o nó errado, e tirei o HDD errado: o que ainda tinha dado, não o que eu queria esvaziar.
Erro 3 e 4, o mkfs sem análise devida. Pra reintegrar o disco no nó novo, formatei. mkfs, limpo. Antes eu até olhei: "tem volume sem cópia? não, zero faulted". Falsa segurança. O Longhorn contava como "cópia" uma réplica parada num disco prestes a sair, e essa era a última cópia viva de um banco interno meu (uma fila de tasks de uns agentes autônomos que rodo). O mkfs passou por cima. Dado vivo, evaporado.
Pra deixar o tamanho do tropeço claro, o antes e depois do storage:
| Nó | Antes | Depois |
|---|---|---|
| A | HDD grande + NVMe | NVMe só (HDD saiu; era o plano, mas no nó errado) |
| B | HDDs + NVMe | HDDs + NVMe (ainda a migrar) |
| C (storage) | 2 HDDs | 2 HDDs + o HDD grande |
O que salvou
Duas coisas, e nenhuma delas foi esperteza minha no momento.
Backup. Um pg_dump que roda todo dia às 6 da manhã num volume separado. Quando fui ver, os backups de dois dias antes estavam com 0 bytes: tinham falhado durante a crise do SSD e não houve nenhum alerta na stack de monitoria (outra lição). Mas o da manhã pegou. Íntegro. Recuperei o banco até ali. Perdi uma janela de horas, mas era dado operacional, recriável.
Não estar sozinho. No meio da bagunça, quando eu já ia "promover" a réplica sobrevivente achando que tinha dado, veio um "calma, valida primeiro se esse disco tem a ver com o banco" (eu conversando com o Claude hehe). Validei. Não tinha dado nenhum ali. Se eu tivesse seguido, teria sobrescrito o backup com vazio. O passo mais perigoso foi barrado por uma pergunta simples antes do irreversível.
Teve até um plot twist bom: os discos do outro nó, que eu achava corrompidos, estavam só montados nos lugares trocados. Remontei por UUID, apontei os caminhos certos, e dezenas de réplicas voltaram. O banco do produto, esse, nunca chegou perto de ser afetado. Ficou saudável o tempo todo, isolado do resto. Pelo menos uma coisa eu tinha feito direito antes.
As lições, aprendidas na marra!
- Monte disco de dados por UUID, nunca por
/dev/sdX. E põenofail, senão um disco que saiu trava o boot inteiro esperando ele. 0 faultednão te dá permissão pra formatar. Antes de qualquermkfsnum disco que vai sair, cheque réplica por réplica se alguma é a última cópia de alguém.- Confirme qual máquina física é qual antes de desligar. Rótulo na cabeça não conta.
- Migração de storage é um nó por vez. Manter redundância durante a janela não é luxo.
- Backup que "rodou com sucesso" pode ter gerado um arquivo de 0 byte. Valide o tamanho, não só o exit code.
- E mantenha alguém olhando. A melhor proteção contra o erro irreversível foi uma pergunta feita por outra pessoa na hora certa.
No fim deu tudo certo. Cluster de pé, banco restaurado, produto intacto. Mas foi por backup e por uma segunda pessoa atenta, não por competência minha naquele momento. Tô deixando registrado mais pra mim do que pra vocês.
Minha stack (pra os curiosos)
O cluster é k3s + Longhorn, rodando em três nós em casa:
| Nó | CPU | RAM | Storage físico | Papel |
|---|---|---|---|---|
| Node 1 | Intel i5-10400 (6c/12t) | 32 GB | NVMe 1 TB (Micron) | control-plane |
| Node 2 | Intel i5-10400 (6c/12t) | 32 GB | SSD 256 GB (sistema) + 3 HDDs (4 TB + 5 TB + 4 TB) | worker |
| Node 3 | 2× Xeon E5-2680 v2 (20c/40t) | 188 GB | SSD 256 GB (sistema) + 2× 2 TB + 12 TB (HDD) | storage / o nó "gordo" |
O Node 3 virou o nó de storage justamente por isso: muita RAM e baia de disco sobrando. Os HDDs do Node 2 ainda vão migrar pra ele numa Fase 2, que agora vou fazer com bem mais calma (e um nó por vez).
E já que você chegou até aqui, o jabá: esse cluster não é só lab. É onde rodam, em produção, dois produtos meus, o zelfy.io (gestão pessoal de verdade num lugar só: finanças, saúde, estudos e reflexões) e o boladecristal.com.br. Pois é, eu quase torrei o storage que segura os meus próprios produtos. A ironia ficou registrada.
Alguém aí já apagou produção (ou quase) numa operação que parecia trivial? Conta a sua.