Pular para o conteúdo
Development

Trazendo dados sanitizados de produção para o dev quando não tem rsync

Por Victor Da Luz•
railssqlitedevopsdev-logblog-manager

O ambiente de dev do blog-manager sempre rodou com quase nada: um usuário seed, dois blogs fixture. Isso é ótimo para a suite de testes automatizados, que usa fixtures de qualquer forma, mas torna o teste manual (bin/dev, clicando pela interface) praticamente inútil, já que não tem histórico real de posts, nenhuma imagem de destaque real, nada que se pareça com o site de verdade que estou gerenciando. Eu queria uma forma de trazer um snapshot real de produção para o dev sem montar isso na mão toda vez.

O app é SQLite, não Postgres, feito deploy via Kamal com o arquivo do banco de dados vivendo num volume bind-mounted (/data/storage no host, /rails/storage no container). Isso na verdade torna tudo mais simples do que um dump/restore de Postgres, já que o banco inteiro é só um arquivo que eu posso copiar.

O que eu construí

Uma rake task, bin/rails data:pull_from_prod:

  1. scp o arquivo SQLite de produção para um diretório temp descartável
  2. Sanitiza no lugar, antes de tocar em qualquer coisa local: zera toda coluna de token/API key criptografada, reseta todas as senhas de usuário para a mesma que db/seeds.rb já usa, limpa a tabela de sessions
  3. Pede confirmação, já que está prestes a sobrescrever storage/development.sqlite3
  4. Também baixa os arquivos do Active Storage, para que as imagens de destaque realmente resolvam localmente
  5. Roda as migrations pendentes, já que o schema de produção pode ficar atrás do que eu tenho no checkout local

A parte da sanitização importa mais do que parece. Este app usa Active Record Encryption em coisas como tokens do GitHub e API keys, e o dev não compartilha as chaves de criptografia de produção, então mesmo se eu deixasse essas colunas intactas, elas seriam só lixo no dev, ilegíveis e propensas a estourar erro no decrypt assim que qualquer coisa as tocasse. Zerá-las é a única opção sensata, não só a segura.

O que me surpreendeu

A primeira execução explodiu na hora: no such column: unsplash_access_key. Produção estava rodando um schema de antes de essa migration ser mergeada localmente, o que faz sentido quando penso a respeito (os deploys de produção ficam atrás da main), mas o SQL de sanitização tinha nomes de coluna fixos no código e assumia que o schema local batia com o schema de produção. Corrigi checando PRAGMA table_info antes de tocar em cada tabela e só zerando as colunas que realmente existem naquele snapshot específico.

Segunda surpresa: usei rsync para baixar os arquivos do Active Storage e recebi rsync: command not found, vindo do shell remoto, repassado de volta pela conexão SSH, o que tornou o erro local (unexpected end of file) bem confuso até eu de fato entrar via SSH e checar. O provisionamento de host do Kamal instala o que o Docker/Kamal precisa e nada além disso; rsync nunca fez parte disso. Troquei por um pipe simples de tar sobre SSH, tar -cf - | tar -xf -, já que tar é o mais perto que existe de garantidamente presente, e funcionou de primeira.

Testando de verdade

Rodei contra o host de produção de verdade, em vez de confiar que o código estava certo. Baixei o banco real, confirmei que as colunas sanitizadas realmente estavam nil, subi o servidor de dev, e fiz login via HTTP com a senha resetada contra o usuário real de produção, recebi um 302 e um cookie de sessão, e então confirmei que o dashboard renderizou os dois blogs reais. É bom ter uma task chata de rodar porque ela simplesmente funciona.

O que vem a seguir

Isso cobre a metade “sem dados realistas” do problema. Existe uma questão em aberto separada, se vale a pena manter o ambiente de staging, considerando que ele é pouco usado e tem exatamente esse mesmo problema de dados escassos, de forma independente. Isso está sendo rastreado separadamente; esse mecanismo de sincronização funciona independente de para que lado isso for.

Leitura relacionada

Você também pode achar útil

RackNerd

RackNerd VPS

Hospedagem VPS econômica para serviços leves que funcionam continuamente.

Como afiliado da RackNerd, ganho com compras qualificadas.

Saiba mais
Proton

Proton Pass

Gerenciador de senhas focado em privacidade, da equipe por trás do Proton Mail.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
AdGuard

AdGuard para iOS

Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.

Como afiliado da AdGuard, ganho com compras qualificadas.

Saiba mais