¿Cómo se gestionan las bases de datos en desarrollo, prueba y producción?

171

Me costó mucho tratar de encontrar buenos ejemplos de cómo administrar esquemas de bases de datos y datos entre servidores de desarrollo, prueba y producción.

Aquí está nuestra configuración. Cada desarrollador tiene una máquina virtual que ejecuta nuestra aplicación y la base de datos MySQL. Es su sandbox personal para hacer lo que quieran. Actualmente, los desarrolladores realizarán un cambio en el esquema SQL y realizarán un volcado de la base de datos en un archivo de texto que comprometerán en SVN.

Queremos implementar un servidor de desarrollo de integración continua que siempre ejecutará el último código comprometido. Si lo hacemos ahora, volverá a cargar la base de datos desde SVN para cada compilación.

Tenemos un servidor de prueba (virtual) que ejecuta "candidatos de lanzamiento". La implementación en el servidor de prueba es actualmente un proceso muy manual, y generalmente implica que cargue el último SQL de SVN y lo modifique. Además, los datos en el servidor de prueba son inconsistentes. Terminas con los datos de prueba que el último desarrollador que confirmó tenía en su servidor sandbox.

Donde todo se rompe es el despliegue a la producción. Como no podemos sobrescribir los datos en vivo con los datos de prueba, esto implica volver a crear manualmente todos los cambios de esquema. Si hubo una gran cantidad de cambios de esquema o scripts de conversión para manipular los datos, esto puede ser realmente complicado.

Si el problema fuera solo el esquema, sería un problema más fácil, pero hay datos "básicos" en la base de datos que también se actualizan durante el desarrollo, como metadatos en las tablas de seguridad y permisos.

Esta es la barrera más grande que veo para avanzar hacia la integración continua y la construcción en un solo paso. ¿Cómo se soluciona esto?


Una pregunta de seguimiento: ¿cómo realiza un seguimiento de las versiones de la base de datos para saber qué scripts ejecutar para actualizar una instancia de base de datos determinada? ¿Una tabla de versiones como Lance menciona debajo del procedimiento estándar?


Gracias por la referencia a Tarantino. No estoy en un entorno .NET, pero su página wiki de DataBaseChangeMangement me pareció muy útil. Especialmente esta presentación de PowerPoint (.ppt)

Voy a escribir un script de Python que verifica los nombres de los *.sqlscripts en un directorio dado contra una tabla en la base de datos y ejecuta los que no están allí en orden en función de un número entero que forma la primera parte del nombre de archivo. Si es una solución bastante simple, como sospecho que será, la publicaré aquí.


Tengo un script de trabajo para esto. Se encarga de inicializar la base de datos si no existe y ejecuta scripts de actualización según sea necesario. También hay conmutadores para borrar una base de datos existente e importar datos de prueba de un archivo. Son alrededor de 200 líneas, por lo que no lo publicaré (aunque podría ponerlo en pastebin si hay interés).

Matt Miller
fuente
"Voy a escribir una secuencia de comandos de Python que verifica los nombres de las secuencias de comandos * .sql en un directorio dado contra una tabla en la base de datos y ejecuta las que no están en orden en función de un número entero que forma la primera parte de el nombre del archivo. Si es una solución bastante simple, como sospecho que será, la publicaré aquí ". Parece que estás implementando flyway.
masterxilo

Respuestas:

53

Hay un par de buenas opciones. No usaría la estrategia "restaurar una copia de seguridad".

  1. Escriba todos los cambios en su esquema y haga que su servidor CI ejecute esos scripts en la base de datos. Tenga una tabla de versiones para realizar un seguimiento de la versión actual de la base de datos y solo ejecute los scripts si son para una versión más nueva.

  2. Utiliza una solución de migración. Estas soluciones varían según el idioma, pero para .NET utilizo Migrator.NET. Esto le permite versionar su base de datos y moverse hacia arriba y hacia abajo entre versiones. Su esquema se especifica en el código C #.

Lance Fisher
fuente
28

Sus desarrolladores necesitan escribir scripts de cambio (cambio de esquema y datos) para cada error / característica en la que trabajan, no simplemente volcar toda la base de datos en el control de origen. Estas secuencias de comandos actualizarán la base de datos de producción actual a la nueva versión en desarrollo.

Su proceso de compilación puede restaurar una copia de la base de datos de producción en un entorno apropiado y ejecutar todos los scripts del control de origen en él, lo que actualizará la base de datos a la versión actual. Hacemos esto a diario para asegurarnos de que todos los scripts se ejecuten correctamente.

tbreffni
fuente
13

Echa un vistazo a cómo Ruby on Rails hace esto.

Primero están los llamados archivos de migración, que básicamente transforman el esquema de la base de datos y los datos de la versión N a la versión N + 1 (o en caso de degradación de la versión N + 1 a N). La base de datos tiene una tabla que indica la versión actual.

Las bases de datos de prueba siempre se limpian antes de las pruebas unitarias y se rellenan con datos fijos de los archivos.

Juha Syrjälä
fuente
10

El libro Refactoring Databases: Evolutionary Database Design puede darle algunas ideas sobre cómo administrar la base de datos. También se puede leer una versión corta en http://martinfowler.com/articles/evodb.html

En un proyecto PHP + MySQL, tuve el número de revisión de la base de datos almacenado en la base de datos, y cuando el programa se conecta a la base de datos, primero verificará la revisión. Si el programa requiere una revisión diferente, abrirá una página para actualizar la base de datos. Cada actualización se especifica en el código PHP, que cambiará el esquema de la base de datos y migrará todos los datos existentes.

Esko Luontola
fuente
5
  • Asigne un nombre a sus bases de datos de la siguiente manera: dev_<<db>> , tst_<<db>> , stg_<<db>> , prd_<<db>>(Obviamente, nunca debe codificar los nombres de bases de datos
  • Por lo tanto, podría implementar incluso los diferentes tipos de bases de datos en el mismo servidor físico (no lo recomiendo, pero es posible que tenga que ... si los recursos son escasos)
  • Asegúrese de poder mover datos entre ellos automáticamente
  • Separar los scripts de creación de db de la población = Siempre debería ser posible recrear el db desde cero y poblarlo (desde la versión antigua de db o la fuente de datos externa)
  • no use cadenas de conexión de código rígido en el código (incluso no en los archivos de configuración): use en las plantillas de cadena de conexión de archivos de configuración, que puede completar dinámicamente, cada reconfiguración de la capa de aplicación que necesita recompilar es MALA
  • use versiones de bases de datos y versiones de objetos db; si puede permitírselo, use productos listos, si no desarrolla algo por su cuenta
  • Rastree cada cambio DDL y guárdelo en alguna tabla de historial ( ejemplo aquí )
  • Copias de seguridad DIARIAS! Pruebe qué tan rápido podría restaurar algo perdido de una copia de seguridad (use scripts de restauración automáticos
  • incluso su base de datos DEV y PROD tienen exactamente el mismo script de creación, tendrá problemas con los datos, así que permita a los desarrolladores crear la copia exacta de prod y jugar con ella (sé que recibiré menos por esto, pero cambie en el la mentalidad y el proceso comercial le costarán mucho menos cuando la mierda golpee al fanático, así que obligue a los codificadores a suscribirse legalmente a lo que sea que haga, pero asegúrese de que este
Yordan Georgiev
fuente
El último punto es el estado de ánimo. Si es necesario, muestra que la definición del proyecto está rota. El desarrollo debe conducir antes de la producción. Si los datos de producción inducen efectos secundarios, muestran problemas mayores. Limpiar los datos de producción. También aclare el último paso con el oficial de protección de datos, si hay alguna razón, como sugiere, de que los datos en vivo deben estar en los sistemas de desarrollo, verifique si esto es legalmente aplicable. Además, una copia exacta de los datos de producción ralentiza en gran medida el desarrollo y la integración. Considere un proceso menos costoso si no puede permitirse ese lujo.
hakre 01 de
La cuestión es que durante el desarrollo simplemente no es posible visualizar todos los casos de esquina en el flujo de control y las variaciones en la calidad de los datos que sucederán en la producción. Si está en un grupo tan grande, para tener problemas legales para eso, debe implementarse algún tipo de solución de enmascaramiento y / o enmascaramiento de datos, que agrega una capa adicional de complejidad, pero aún debe preservar los aspectos de calidad de datos que causaron el error en primer lugar de todos modos ...
Yordan Georgiev
4

Esto es algo con lo que estoy constantemente insatisfecho: nuestra solución a este problema es. Durante varios años mantuvimos un script de cambio separado para cada versión. Este script contendría los deltas de la última versión de producción. Con cada lanzamiento de la aplicación, el número de versión se incrementaría, dando algo como lo siguiente:

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

Esto funcionó bastante bien hasta que comenzamos a mantener dos líneas de desarrollo: Trunk / Mainline para nuevos desarrollos, y una rama de mantenimiento para corrección de errores, mejoras a corto plazo, etc. Inevitablemente, surgió la necesidad de realizar cambios en el esquema en la rama. En este punto, ya teníamos dbChanges_n + 1.sql en el tronco, por lo que terminamos con un esquema como el siguiente:

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

Nuevamente, esto funcionó bastante bien, hasta que un día miramos hacia arriba y vimos 42 scripts delta en la línea principal y 10 en la rama. ARGH!

En estos días simplemente mantenemos un script delta y dejamos que SVN lo versione, es decir, sobrescribimos el script con cada lanzamiento. Y evitamos hacer cambios de esquema en las ramas.

Por lo tanto, tampoco estoy satisfecho con esto. Me gusta mucho el concepto de migraciones de Rails. Me he fascinado bastante con LiquiBase . Admite el concepto de refactorizaciones incrementales de la base de datos. Vale la pena echarle un vistazo y lo veré en detalle pronto. ¿Alguien tiene experiencia con eso? Me daría mucha curiosidad saber de tus resultados.

Matt Stine
fuente
4

También puede considerar el uso de una herramienta como SQL Compare to script, la diferencia entre varias versiones de una base de datos, lo que le permite migrar rápidamente entre versiones

Rad
fuente
3

Tenemos una configuración muy similar al OP.

Los desarrolladores se desarrollan en máquinas virtuales con bases de datos privadas.

[Los desarrolladores pronto se comprometerán en sucursales privadas]

Las pruebas se ejecutan en diferentes máquinas (en realidad en máquinas virtuales alojadas en un servidor) [Pronto será ejecutado por el servidor Hudson CI]

Pruebe cargando el volcado de referencia en la base de datos. Aplique los parches del esquema de los desarrolladores y luego aplique los parches de datos de los desarrolladores

Luego ejecute las pruebas unitarias y del sistema.

La producción se implementa a los clientes como instaladores.

Lo que hacemos:

Tomamos un volcado de esquema de nuestra base de datos sandbox. Luego un volcado de datos sql. Diferimos eso a la línea de base anterior. ese par de deltas es actualizar n-1 a n.

Configuramos los volcados y deltas.

Entonces, para instalar la versión N CLEAN, ejecutamos el volcado en una base de datos vacía. Para parchear, aplique los parches intermedios.

(Juha mencionó que la idea de Rail de tener una tabla que grabe la versión actual de DB es buena y debería hacer que la instalación de actualizaciones sea menos complicada).

Los deltas y los volcados deben revisarse antes de la prueba beta. No puedo ver nada al respecto, ya que he visto a los desarrolladores insertar cuentas de prueba en la base de datos por sí mismos.

Tim Williscroft
fuente
3

Me temo que estoy de acuerdo con otros carteles. Los desarrolladores necesitan escribir sus cambios.

En muchos casos, una ALTER TABLE simple no funcionará, también debe modificar los datos existentes: los desarrolladores deben pensar qué migraciones son necesarias y asegurarse de que estén escritas correctamente (por supuesto, debe probar esto cuidadosamente en algún momento el ciclo de lanzamiento).

Además, si tiene algún sentido, también hará que sus desarrolladores hagan retrocesos de script para sus cambios para que puedan revertirse si es necesario. Esto también debe probarse, para garantizar que su reversión no solo se ejecute sin errores, sino que deje la base de datos en el mismo estado en que se encontraba anteriormente (esto no siempre es posible o deseable, pero es una buena regla la mayor parte del tiempo) .

Cómo lo conectas a un servidor CI, no lo sé. Tal vez su servidor CI necesita tener una instantánea de compilación conocida, a la que revierte cada noche y luego aplica todos los cambios desde entonces. Probablemente sea lo mejor, de lo contrario, un script de migración roto no solo romperá la compilación de esa noche, sino todos los posteriores.

MarkR
fuente
1

Eche un vistazo a dbdeploy , ya hay herramientas Java y .net disponibles, puede seguir sus estándares para los diseños de archivos SQL y la tabla de versiones de esquema y escribir su versión de Python.

Dave Marshall
fuente
1

Estamos usando la línea de comandos mysql-diff : genera una diferencia entre dos esquemas de base de datos (de Live DB o script) como ALTER script. mysql-diff se ejecuta al inicio de la aplicación, y si el esquema cambia, informa al desarrollador. Por lo tanto, los desarrolladores no necesitan escribir ALTER manualmente, las actualizaciones de esquema se producen de forma semiautomática.

stepancheg
fuente
0

He escrito una herramienta que (al conectarse a Open DBDiff ) compara los esquemas de la base de datos y le sugerirá scripts de migración. Si realiza un cambio que elimina o modifica datos, arrojará un error, pero proporcionará una sugerencia para el script (por ejemplo, cuando falta una columna en el nuevo esquema, verificará si la columna ha cambiado de nombre y creará xx - generado script.sql.suggestion que contiene una declaración de cambio de nombre).

http://code.google.com/p/migrationscriptgenerator/ Solo SQL Server me temo :( También es bastante alfa, pero tiene MUY baja fricción (particularmente si lo combinas con Tarantino o http://code.google .com / p / simplescriptrunner / )

La forma en que lo uso es tener un proyecto de scripts SQL en su .sln. También tiene una base de datos db_next localmente a la que realiza sus cambios (usando Management Studio o NHibernate Schema Export o LinqToSql CreateDatabase o algo así). Luego ejecuta migrationscriptgenerator con las bases de datos _dev y _next, que crea. los scripts de actualización de SQL para migrar.

revs mcintyre321
fuente
0

Para la base de datos oracle utilizamos las herramientas oracle-ddl2svn .

Esta herramienta automatizó el siguiente proceso

  1. para cada esquema db obtener esquema ddls
  2. ponlo bajo version contol

cambios entre instancias resueltos manualmente

popalka
fuente