1. Introducción a Atlas
Atlas es una herramienta independiente del lenguaje diseñada específicamente para gestionar y migrar esquemas de bases de datos utilizando principios modernos de DevOps. Proporciona dos opciones de flujo de trabajo:
- Declarativo: Similar a Terraform, Atlas compara el estado actual de la base de datos con el estado deseado definido usando HCL, SQL, u ORM schema. Con base en esta comparación, genera y ejecuta un plan de migración para llevar la base de datos a su estado deseado.
- Versionado: A diferencia de otras herramientas, Atlas planifica automáticamente las migraciones de esquema para ti. Los usuarios pueden describir su esquema de base de datos deseado usando HCL, SQL o su ORM elegido, y con Atlas, planificar, revisar y aplicar las migraciones necesarias a la base de datos.
Una ventaja clave de Atlas es su simplificación de la complejidad de la gestión de bases de datos, facilitando el control de versiones, la colaboración y la implementación.
2. Instalación de Atlas
Antes de usar Atlas para gestionar las versiones de la base de datos, necesitamos instalarlo. A continuación se detallan los pasos de instalación para diferentes plataformas.
2.1 Instalación en macOS + Linux
En sistemas macOS o Linux, puedes descargar e instalar la última versión de Atlas utilizando el siguiente comando de línea de comandos:
curl -sSf https://atlasgo.sh | sh
Este comando detectará automáticamente la versión del sistema operativo, descargará la versión de compilación adecuada, y colocará el archivo binario de Atlas en la ruta ejecutable.
2.2 Instalación a través de Homebrew
Si estás utilizando macOS y ya has instalado el gestor de paquetes Homebrew, instalar Atlas es tan simple como ejecutar el comando:
brew install ariga/tap/atlas
Esto descargará la última versión de Atlas desde el repositorio de Homebrew y la instalará.
2.3 Instalación con Docker
Instalar y ejecutar Atlas a través de Docker es un método rápido y conveniente, especialmente para pruebas temporales o para usuarios que prefieren no instalar software adicional en su sistema host.
Primero, descarga la imagen de Atlas para Docker:
docker pull arigaio/atlas
Luego, puedes ejecutar un comando de ayuda para confirmar una instalación exitosa:
docker run --rm arigaio/atlas --help
Si el contenedor necesita acceder a la red del host o a directorios locales, utiliza la bandera --net=host
y monta los directorios requeridos:
docker run --rm --net=host \
-v $(pwd)/migrations:/migrations \
arigaio/atlas migrate apply \
--url "mysql://root:pass@:3306/test"
2.4 Instalación en Windows
Descarga el archivo binario, https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe, y añade la ruta de instalación a la variable de entorno PATH del sistema.
3. Exportar la Estructura de la Tabla de la Base de Datos Existente Usando Atlas
Atlas proporciona el comando atlas schema inspect
, que se puede utilizar para exportar la estructura de una base de datos existente. Este comando admite la lectura de descripciones de la base de datos desde la URL de la base de datos y las muestra en tres formatos diferentes: el formato predeterminado Atlas HCL, formato SQL y formato JSON. En esta guía, mostraremos cómo utilizar los formatos Atlas HCL y SQL, ya que el formato JSON se utiliza típicamente para procesar la salida con jq
.
Para inspeccionar una instancia local en ejecución de MySQL y escribir la salida en un archivo llamado schema.hcl
, utilice el siguiente comando:
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
Abra el archivo schema.hcl
para ver la definición de la estructura de la tabla de Atlas que describe la base de datos (HCL es un formato de configuración de estructura de tabla independiente de la base de datos definido por Atlas). Por ejemplo, este archivo contendrá el siguiente contenido:
table "users" {
schema = schema.example
column "id" {
null = false
type = int
}
column "name" {
null = true
type = varchar(100)
}
primary_key {
columns = [column.id]
}
}
Este bloque de código representa una estructura de tabla con columnas id
y name
. El campo schema
hace referencia a la definición del modelo example
definido en otro lugar en este documento. Además, el subbloque primary_key
especifica la columna id
como la clave primaria para la tabla. Atlas se esfuerza por imitar la sintaxis de la base de datos en la que se está operando. En este ejemplo, la columna id
tiene un tipo de int
, mientras que la columna name
tiene un tipo de varchar(100)
.
De manera similar, para exportar una definición de modelo SQL de la base de datos, puede utilizar el siguiente comando:
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}' > schema.sql
Abra el archivo schema.sql
para ver la descripción SQL de la base de datos, que típicamente contiene algunas declaraciones CREATE TABLE.
Este enfoque facilita entender los detalles de la estructura de la tabla de la base de datos existente y proporciona una referencia precisa para migraciones versionadas subsiguientes.
4.1 Flujo de Trabajo Declarativo
El Flujo de Trabajo Declarativo de Atlas permite a los usuarios definir de forma declarativa el estado final deseado de la base de datos. Los usuarios solo necesitan describir cuál debería ser el estado final del esquema de la base de datos, y la herramienta Atlas generará y ejecutará automáticamente planes de migración para realizar la transición de manera segura del estado actual del esquema de la base de datos a este estado esperado.
A continuación, se muestra cómo utilizar el Flujo de Trabajo Declarativo para definir y lograr el estado deseado de la base de datos:
4.1.1 Definir la Estructura de la Tabla de Destino
Primero, necesitas crear un archivo que defina la estructura esperada de la base de datos, que puede estar en formato HCL, SQL o ORM (Mapeo Objeto-Relacional).
Tomando como ejemplo el formato HCL, define una nueva tabla blog_posts
:
table "blog_posts" {
schema = schema.example
column "id" {
null = false
type = int
}
column "title" {
null = true
type = varchar(100)
}
column "body" {
null = true
type = text
}
column "author_id" {
null = true
type = int
}
primary_key {
columns = [column.id]
}
foreign_key "author_fk" {
columns = [column.author_id]
ref_columns = [table.users.column.id]
}
}
Nota: El formato de sintaxis de HCL se cubrirá en una sección posterior.
4.1.2 Realizar la Migración Utilizando la Herramienta Atlas
Una vez completada la definición de la estructura de la tabla de la base de datos, puedes utilizar el comando schema apply
de Atlas para realizar la migración.
atlas schema apply \
-u "mysql://root:pass@localhost:3306/example" \
--to file://schema.hcl
Después de ejecutar el comando anterior, Atlas comparará el esquema de la base de datos existente con el esquema definido en el archivo, generará un plan de migración y pedirá al usuario la confirmación para ejecutarlo. Una vez que el usuario confirme el plan de ejecución, Atlas realizará la migración en la base de datos y la actualizará al estado deseado.
4.2 Flujo de Trabajo Versionado
El flujo de trabajo versionado es otro modo de uso compatible con Atlas, a veces llamado "migración basada en cambios". Es adecuado para escenarios en los que los cambios en el esquema de la base de datos deben estar versionados y revisados en el proceso de revisión de código.
Los pasos del flujo de trabajo versionado incluyen:
4.2.1 Calcular diferencias
Antes de comenzar la migración, es necesario comparar la estructura actual de la base de datos con el estado deseado y determinar las diferencias entre ambos. Esto se puede lograr ejecutando el comando atlas migrate diff
.
atlas migrate diff create_blog_posts \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://mysql/8/example"
El parámetro --dir
especifica la URL de la carpeta de migración, con un valor predeterminado de file://migrations
. El parámetro --to
especifica la URL del estado deseado (por ejemplo, la base de datos del entorno de desarrollo), y --dev-url
proporciona una URL para una base de datos de desarrollo utilizada para calcular las diferencias (ten en cuenta que este --dev-url
necesita especificar una base de datos vacía que Atlas utiliza para calcular las diferencias).
Consejo: Si deseas generar archivos SQL, consulta la sección anterior para configurar el formato usando el parámetro
--format
.
4.2.2 Aplicar cambios de migración
Después de que se complete el cálculo de diferencias, Atlas generará dos archivos de migración guardados en la carpeta migrations
. Por ejemplo, si el formato seleccionado es SQL, los archivos generados por el comando diff
, como el siguiente archivo SQL, contendrán comandos de migración para crear una nueva tabla:
-- crear tabla "blog_posts"
CREATE TABLE `blog_posts` (
`id` int NOT NULL,
`title` varchar(100) DEFAULT NULL,
`body` text DEFAULT NULL,
`author_id` int NULL REFERENCES `users`(id),
PRIMARY KEY (`id`)
);
Una vez generados los archivos de migración, puedes utilizar herramientas de control de versiones (por ejemplo, Git) para gestionar estos cambios. Este enfoque permite realizar numerosas modificaciones en la estructura de tabla de la base de datos en el entorno de desarrollo y, cuando llegue el momento de la publicación, comparar el entorno de desarrollo y el entorno UAT utilizando comandos de Atlas para generar archivos de migración de estructura de tabla de base de datos. Estos archivos de migración luego se pueden aplicar a los entornos UAT y producción para actualizar la base de datos.
Estos dos flujos de trabajo, Declarativo y Versionado, proporcionan flexibilidad para diferentes modos de desarrollo e implementación, permitiendo a los equipos elegir el método que mejor se adapte a las necesidades de su proyecto para gestionar los cambios en el esquema de la base de datos.
5. Descripción del formato HCL
5.1 Introducción
HCL es un lenguaje declarativo utilizado para describir las definiciones de la estructura de las tablas de la base de datos. Atlas utiliza el formato HCL para escribir esquemas de base de datos, proporcionando una estructura sólida para describir diferentes aspectos de la base de datos. La ventaja de HCL radica en su legibilidad, facilidad de mantenimiento y soporte para funciones como la inyección de variables y anotaciones adicionales.
Consejo: Si tu proyecto necesita adaptarse a múltiples bases de datos, describir las estructuras de tabla de forma independiente de la base de datos utilizando HCL puede ser muy conveniente.
5.2 Objeto schema
El objeto schema
se utiliza para describir un esquema de base de datos. En MySQL y SQLite, representa la BASE DE DATOS
, mientras que en PostgreSQL, representa el ESQUEMA
. Un archivo HCL puede contener uno o más objetos schema
.
schema "public" {
comment = "Un comentario de esquema"
}
schema "private" {}
5.3 Objeto table
El objeto table
se utiliza para describir una tabla en una base de datos SQL, incluyendo columnas, índices, restricciones y diversas propiedades adicionales admitidas por distintos controladores de base de datos.
table "users" {
schema = schema.public
column "id" {
type = int
}
column "name" {
type = varchar(255)
}
column "manager_id" {
type = int
}
primary_key {
columns = [
column.id
]
}
index "idx_name" {
columns = [
column.name
]
unique = true
}
foreign_key "manager_fk" {
columns = [column.manager_id]
ref_columns = [table.users.column.id]
on_delete = CASCADE
on_update = NO_ACTION
}
}
5.4 Objeto column
El objeto column
es un subrecurso de table
utilizado para definir las columnas en la tabla.
column "name" {
type = text
null = false
}
column "age" {
type = integer
default = 42
}
column "active" {
type = tinyint(1)
default = true
}
5.5 Objeto primary_key
El objeto primary_key
es un subrecurso de table
que define la clave primaria de la tabla.
primary_key {
columns = [column.id]
}
5.6 Objeto foreign_key
El objeto foreign_key
es un subrecurso de table
que define columnas que hacen referencia a columnas en otras tablas.
table "orders" {
schema = schema.market
// ...
column "owner_id" {
type = integer
}
foreign_key "owner_id" {
columns = [column.owner_id]
ref_columns = [table.users.column.id]
on_update = NO_ACTION
on_delete = NO_ACTION
}
}
5.7 Objeto index
El objeto index
representa un índice en la tabla.
index "idx_name" {
columns = [
column.name
]
unique = true
}