Como você gerencia bancos de dados em desenvolvimento, teste e produção?

171

Tive dificuldade para encontrar bons exemplos de como gerenciar esquemas e dados de banco de dados entre servidores de desenvolvimento, teste e produção.

Aqui está a nossa configuração. Cada desenvolvedor tem uma máquina virtual executando nosso aplicativo e o banco de dados MySQL. É sua caixa de areia pessoal fazer o que quiserem. Atualmente, os desenvolvedores fazem uma alteração no esquema SQL e fazem um despejo do banco de dados em um arquivo de texto que eles confirmam no SVN.

Queremos implantar um servidor de desenvolvimento de integração contínua que sempre esteja executando o código confirmado mais recente. Se fizermos isso agora, ele recarregará o banco de dados do SVN para cada build.

Temos um servidor de teste (virtual) que executa "liberar candidatos". A implantação no servidor de teste atualmente é um processo muito manual e geralmente envolve o carregamento do SQL mais recente do SVN e o aprimoramento. Além disso, os dados no servidor de teste são inconsistentes. Você acaba com quaisquer dados de teste que o último desenvolvedor confirmar no seu servidor sandbox.

Onde tudo quebra é a implantação na produção. Como não podemos sobrescrever os dados ativos com dados de teste, isso envolve recriar manualmente todas as alterações de esquema. Se houver um grande número de alterações de esquema ou scripts de conversão para manipular os dados, isso pode ficar muito complicado.

Se o problema fosse apenas o esquema, seria um problema mais fácil, mas também existem dados "básicos" no banco de dados que são atualizados durante o desenvolvimento, como metadados nas tabelas de segurança e permissões.

Essa é a maior barreira que vejo ao avançar para a integração contínua e a criação de uma etapa. Como você resolve isso?


Uma pergunta de acompanhamento: como você controla as versões do banco de dados para saber quais scripts executar para atualizar uma determinada instância de banco de dados? Uma tabela de versões como Lance menciona abaixo do procedimento padrão?


Obrigado pela referência a Tarantino. Não estou em um ambiente .NET, mas achei a página wiki do DataBaseChangeMangement muito útil. Especialmente esta apresentação em Powerpoint (.ppt)

Vou escrever um script Python que verifica os nomes dos *.sqlscripts em um determinado diretório em uma tabela no banco de dados e executa os que não estão lá em ordem, com base em um número inteiro que forma a primeira parte do nome do arquivo. Se for uma solução bastante simples, como suspeito, será postada aqui.


Eu tenho um script de trabalho para isso. Ele lida com a inicialização do banco de dados, se ele não existir, e com a execução de scripts de atualização, conforme necessário. Também existem opções para limpar um banco de dados existente e importar dados de teste de um arquivo. São cerca de 200 linhas, por isso não vou publicá-lo (embora eu possa colocá-lo no pastebin, se houver interesse).

Matt Miller
fonte
"Vou escrever um script Python que verifica os nomes dos scripts * .sql em um determinado diretório em uma tabela no banco de dados e executa os que não estão lá em ordem, com base em um número inteiro que forma a primeira parte do nome do arquivo. Se for uma solução bastante simples, como suspeito, será publicada aqui. " Parece que você está implementando o flyway.
Masterdilo

Respostas:

53

Existem algumas boas opções. Eu não usaria a estratégia "restaurar um backup".

  1. Faça o script de todas as alterações no esquema e faça com que o servidor de IC execute esses scripts no banco de dados. Tenha uma tabela de versões para acompanhar a versão atual do banco de dados e execute os scripts apenas se forem de uma versão mais recente.

  2. Use uma solução de migração. Essas soluções variam de acordo com o idioma, mas, para o .NET, eu uso o Migrator.NET. Isso permite que você versão seu banco de dados e mover para cima e para baixo entre versões. Seu esquema é especificado no código C #.

Lance Fisher
fonte
28

Seus desenvolvedores precisam escrever scripts de alteração (esquema e alteração de dados) para cada bug / recurso em que trabalham, não apenas despejar todo o banco de dados no controle de origem. Esses scripts atualizarão o banco de dados de produção atual para a nova versão em desenvolvimento.

Seu processo de construção pode restaurar uma cópia do banco de dados de produção em um ambiente apropriado e executar todos os scripts do controle de origem, o que atualizará o banco de dados para a versão atual. Fazemos isso diariamente para garantir que todos os scripts sejam executados corretamente.

tbreffni
fonte
13

Veja como o Ruby on Rails faz isso.

Primeiro, existem os chamados arquivos de migração, que basicamente transformam o esquema e os dados do banco de dados da versão N para a versão N + 1 (ou, no caso de fazer o downgrade da versão N + 1 para N). O banco de dados possui uma tabela que informa a versão atual.

Os bancos de dados de teste são sempre limpos antes dos testes de unidade e preenchidos com dados fixos de arquivos.

Juha Syrjälä
fonte
10

O livro Refatorando Bancos de Dados: Design Evolucionário de Banco de Dados pode fornecer algumas idéias sobre como gerenciar o banco de dados. Uma versão curta também pode ser lida em http://martinfowler.com/articles/evodb.html

Em um projeto PHP + MySQL, eu tinha o número da revisão do banco de dados armazenado no banco de dados e, quando o programa se conecta ao banco de dados, ele primeiro verifica a revisão. Se o programa exigir uma revisão diferente, ele abrirá uma página para atualizar o banco de dados. Cada atualização é especificada no código PHP, que altera o esquema do banco de dados e migra todos os dados existentes.

Esko Luontola
fonte
5
  • Nomeie seus bancos de dados da seguinte maneira - dev_<<db>> , tst_<<db>> , stg_<<db>> , prd_<<db>>(Obviamente, você nunca deve codificar nomes de banco de dados
  • Assim, você seria capaz de implantar até mesmo os diferentes tipos de bancos de dados no mesmo servidor físico (eu não recomendo isso, mas você pode precisar ... se os recursos estiverem escassos)
  • Certifique-se de poder mover dados entre os dados automaticamente
  • Separar os scripts de criação de banco de dados da população = sempre deve ser possível recriar o banco de dados a partir do zero e preenchê-lo (da versão antiga do banco de dados ou da fonte de dados externa
  • não use cadeias de conexão de código fixo no código (mesmo que não nos arquivos de configuração) - use nos modelos de cadeia de conexão de arquivos de configuração, que você preenche dinamicamente, cada reconfiguração do application_layer que precisa ser recompilada é BAD
  • use versionamento de banco de dados e versionamento de objetos db - se você puder pagar, use produtos prontos, se não desenvolver algo por conta própria
  • rastreie cada alteração DDL e salve-a em alguma tabela de histórico ( exemplo aqui )
  • Backups diários! Teste o quão rápido você seria capaz de restaurar algo perdido em um backup (use scripts de restauração automática
  • mesmo seu banco de dados DEV e o PROD têm exatamente o mesmo script de criação, você terá problemas com os dados; portanto, permita que os desenvolvedores criem a cópia exata do produto e brinque com ele (eu sei que vou receber desvantagens por esse, mas alterações no a mentalidade e o processo de negócios custarão muito menos quando a merda atingir o ventilador - forçar os codificadores a assinar legalmente o que for necessário, mas garanta que este
Yordan Georgiev
fonte
O último ponto é de fato o humor. Se necessário, mostra que a definição do projeto está quebrada. O desenvolvimento deve liderar antes da produção. Se os dados de produção induzem efeitos colaterais, mostram problemas maiores. Limpe os dados de produção. Esclareça também a última etapa com o responsável pela proteção de dados, se houver motivos - como você sugere - que os dados ativos precisam estar em sistemas de desenvolvimento, verifique se isso é legalmente aplicável. Além disso, uma cópia exata dos dados de produção diminui o desenvolvimento e a integração em grande parte. Considere um processo menos oneroso se você não puder pagar esse luxo.
hakre 01/07/19
O fato é que durante o desenvolvimento simplesmente nem é possível visualizar todos os casos extremos no fluxo de controle e as variações na qualidade dos dados que acontecerão na produção. Se você estiver em uma corporação tão grande, é necessário implementar questões legais para isso, além de algum tipo de solução de embaralhamento e / ou mascaramento de dados, o que adiciona uma camada adicional de complexidade, mas ainda deve preservar os aspectos de qualidade dos dados que causaram o erro em primeiro lugar de qualquer maneira ...
Yordan Georgiev
4

Isso é algo com o qual estou constantemente insatisfeito - nossa solução para esse problema. Por vários anos, mantivemos um script de alteração separado para cada versão. Este script conteria os deltas da última versão de produção. A cada versão do aplicativo, o número da versão aumentava, fornecendo algo como o seguinte:

  • dbChanges_1.sql
  • dbChanges_2.sql
  • ...
  • dbChanges_n.sql

Isso funcionou bem o suficiente até que começamos a manter duas linhas de desenvolvimento: Trunk / Mainline para novo desenvolvimento e uma ramificação de manutenção para correções de bugs, aprimoramentos de curto prazo etc. Inevitavelmente, surgiu a necessidade de fazer alterações no esquema na ramificação. Nesse ponto, já tínhamos dbChanges_n + 1.sql no tronco, então acabamos seguindo um esquema como o seguinte:

  • dbChanges_n.1.sql
  • dbChanges_n.2.sql
  • ...
  • dbChanges_n.3.sql

Novamente, isso funcionou bem o suficiente, até que um dia procuramos e vimos 42 scripts delta na linha principal e 10 na filial. ARGH!

Hoje em dia, simplesmente mantemos um script delta e deixamos o SVN versão - ou seja, substituímos o script a cada versão. E evitamos fazer alterações de esquema nas ramificações.

Então, eu também não estou satisfeito com isso. Eu realmente gosto do conceito de migrações do Rails. Fiquei bastante fascinado com o LiquiBase . Ele suporta o conceito de refatoração incremental de banco de dados. Vale a pena dar uma olhada e em breve vou ver isso em detalhes. Alguém tem experiência com isso? Eu ficaria muito curioso em saber sobre seus resultados.

Matt Stine
fonte
4

Você também pode usar uma ferramenta como o SQL Compare para escrever a diferença entre várias versões de um banco de dados, permitindo migrar rapidamente entre versões

Rad
fonte
3

Temos uma configuração muito semelhante ao OP.

Os desenvolvedores desenvolvem em VMs com bancos de dados privados.

[Em breve, os desenvolvedores se comprometerão em filiais privadas]

O teste é executado em máquinas diferentes (na verdade, nas VMs hospedadas em um servidor) [em breve será executado pelo servidor Hudson CI]

Teste carregando o dump de referência no db. Aplique os patches de esquema dos desenvolvedores e aplique os patches de dados dos desenvolvedores

Em seguida, execute os testes de unidade e sistema.

A produção é implantada nos clientes como instaladores.

O que nós fazemos:

Tomamos um despejo de esquema do nosso banco de dados de sandbox. Em seguida, um dump de dados sql. Diferenciamos isso da linha de base anterior. esse par de deltas é atualizar n-1 para n.

nós configuramos os dumps e deltas.

Portanto, para instalar a versão N CLEAN, executamos o dump em um db vazio. Para aplicar patches, aplique os patches intermediários.

(Juha mencionou a ideia de Rail de ter uma tabela gravando a versão atual do banco de dados é boa e deve tornar a instalação das atualizações menos complicada.)

Deltas e lixões devem ser revistos antes do teste beta. Não vejo como contornar isso, pois vi desenvolvedores inserirem contas de teste no banco de dados por conta própria.

Tim Williscroft
fonte
3

Receio estar de acordo com outros pôsteres. Os desenvolvedores precisam criar um script de suas alterações.

Em muitos casos, um ALTER TABLE simples não funciona, você também precisa modificar os dados existentes - os desenvolvedores precisam pensar sobre quais migrações são necessárias e garantir que estejam com o script correto (é claro que você deve testá-las com cuidado em algum momento) o ciclo de lançamento).

Além disso, se você tiver algum sentido, você também fará com que seus desenvolvedores criem reversões de scripts para as alterações, para que possam ser revertidos, se necessário. Isso também deve ser testado, para garantir que sua reversão não seja executada apenas sem erros, mas deixe o banco de dados no mesmo estado em que estava anteriormente (isso nem sempre é possível ou desejável, mas é uma boa regra na maioria das vezes) .

Como você conecta isso a um servidor de IC, eu não sei. Talvez o servidor de IC precise ter um instantâneo de construção conhecido, o qual reverte a cada noite e depois aplica todas as alterações desde então. Provavelmente, isso é melhor, caso contrário, um script de migração quebrado não quebrará apenas a compilação daquela noite, mas todas as subseqüentes.

MarkR
fonte
1

Confira o dbdeploy , já existem ferramentas Java e .net disponíveis, você pode seguir os padrões para layouts de arquivos SQL e tabela de versões de esquema e escrever sua versão python.

Dave Marshall
fonte
1

Estamos usando a linha de comando mysql-diff : gera uma diferença entre dois esquemas de banco de dados (do banco de dados ou script ativo) como script ALTER. O mysql-diff é executado no início do aplicativo e, se o esquema for alterado, ele será reportado ao desenvolvedor. Portanto, os desenvolvedores não precisam escrever ALTERs manualmente, as atualizações de esquema acontecem semiautomáticas.

stepancheg
fonte
0

Eu escrevi uma ferramenta que (conectando-se ao Open DBDiff ) compara esquemas de banco de dados e sugere scripts de migração para você. Se você fizer uma alteração que exclua ou modifique os dados, ocorrerá um erro, mas fornecerá uma sugestão para o script (por exemplo, quando uma coluna estiver ausente no novo esquema, ele verificará se a coluna foi renomeada e criará xx - gerado script.sql.suggestion contendo uma declaração de renomeação).

http://code.google.com/p/migrationscriptgenerator/ Apenas para SQL Server Receio :( Também é bastante alfa, mas é muito baixo atrito (principalmente se você combiná-lo com Tarantino ou http://code.google .com / p / simplescriptrunner / )

O jeito que eu uso é ter um projeto de scripts SQL no seu .sln. Você também tem um banco de dados db_next localmente no qual faz alterações (usando o Management Studio ou o NHibernate Schema Export ou o LinqToSql CreateDatabase ou algo assim). Em seguida, você executa o migrationscriptgenerator com os bancos de dados _dev e _next, que são criados. os scripts de atualização SQL para a migração.

mcintyre321
fonte
0

Para o banco de dados oracle, usamos as ferramentas oracle-ddl2svn .

Essa ferramenta automatizou o próximo processo

  1. para cada esquema db obter ddls esquema
  2. colocá-lo na versão contol

mudanças entre instâncias resolvidas manualmente

popalka
fonte