Preinicialización de bases de datos con esquema y datos al inicio para entornos de desarrollo
La preinicialización (pre-seeding) de bases de datos con datos y esquemas esenciales durante el desarrollo local es una práctica común para mejorar el flujo de trabajo de desarrollo y pruebas. Al simular escenarios del mundo real, esta práctica ayuda a detectar problemas del frontend a tiempo, garantiza la alineación entre los administradores de bases de datos y los ingenieros de software, y facilita una colaboración más fluida. La preinicialización ofrece beneficios como despliegues seguros, coherencia entre entornos y detección temprana de problemas, mejorando en última instancia el proceso de desarrollo general.
En esta guía, aprenderás a:
- Usar Docker para iniciar un contenedor de Postgres
- Preinicializar Postgres usando un script SQL
- Preinicializar Postgres copiando archivos SQL en la imagen de Docker
- Preinicializar Postgres usando código JavaScript
Uso de Postgres con Docker
La imagen oficial de Docker para Postgres proporciona una forma conveniente de ejecutar la base de datos Postgres en tu máquina de desarrollo. Una imagen Docker de Postgres es un entorno preconfigurado que encapsula el sistema de bases de datos PostgreSQL. Es una unidad autónoma lista para ejecutarse en un contenedor Docker. Al usar esta imagen, puedes configurar una instancia de Postgres de manera rápida y directa, sin necesidad de realizar configuraciones manuales.
Requisitos previos
Se requieren los siguientes requisitos previos para seguir esta guía práctica:
Iniciar Postgres
Inicia una demostración rápida de Postgres siguiendo estos pasos:
Abre la terminal y ejecuta el siguiente comando para iniciar un contenedor de Postgres.
Este ejemplo iniciará un contenedor de Postgres, expondrá el puerto
5432en el host para permitir que una aplicación que se ejecuta de forma nativa se conecte a él con la contraseñamysecretpassword.$ docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgresVerifica que Postgres esté en funcionamiento seleccionando el contenedor y revisando los registros en el panel de Docker Desktop.
PostgreSQL Database directory appears to contain a database; Skipping initialization 2024-09-08 09:09:47.136 UTC [1] LOG: starting PostgreSQL 16.4 (Debian 16.4-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 2024-09-08 09:09:47.137 UTC [1] LOG: listening on IPv6 address "::", port 5432 2024-09-08 09:09:47.139 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" 2024-09-08 09:09:47.142 UTC [29] LOG: database system was shut down at 2024-09-08 09:07:09 UTC 2024-09-08 09:09:47.148 UTC [1] LOG: database system is ready to accept connectionsConéctate a Postgres desde el sistema local.
psqles la consola interactiva de PostgreSQL que se utiliza para conectarse a una base de datos Postgres y te permite comenzar a ejecutar comandos SQL. Asumiendo que ya tienes instalada la utilidadpsqlen tu sistema local, es hora de conectarse a la base de datos. Ejecuta el siguiente comando en tu terminal local:$ docker exec -it postgres psql -h localhost -U postgresAhora puedes ejecutar cualquier consulta o comando SQL que necesites dentro del prompt de
psql.Usa
\qo\quitpara salir de la consola interactiva de Postgres.
Preinicializar la base de datos Postgres usando un script SQL
Una vez que te hayas familiarizado con Postgres, es hora de ver cómo preinicializarlo con datos de ejemplo. En esta demostración, primero crearás un script con comandos SQL. El script define la base de datos y la estructura de la tabla, e inserta datos de ejemplo. Luego te conectarás a la base de datos para verificar los datos.
Asumiendo que tienes una instancia de base de datos Postgres en funcionamiento, sigue estos pasos para inicializar la base de datos.
Crea un archivo vacío llamado
seed.sqly agrega el siguiente contenido.CREATE DATABASE sampledb; \c sampledb CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) UNIQUE ); INSERT INTO users (name, email) VALUES ('Alpha', '[email protected]'), ('Beta', '[email protected]'), ('Gamma', '[email protected]');El script SQL crea una nueva base de datos llamada
sampledb, se conecta a ella y crea una tablausers. La tabla incluye unidautoincremental como clave primaria, un camponamecon una longitud máxima de 50 caracteres y un campoemailúnico de hasta 100 caracteres.Después de crear la tabla, el comando
INSERTintroduce tres usuarios en la tablauserscon sus respectivos nombres y correos electrónicos. Esta configuración establece una estructura de base de datos básica para almacenar información de usuarios con direcciones de correo electrónico únicas.Inicializar la base de datos.
Es hora de enviar el contenido de
seed.sqldirectamente a la base de datos. El comando se utiliza para ejecutar el script SQL llamadoseed.sqlen la base de datos Postgres llamadasampledb.$ cat seed.sql | docker exec -i postgres psql -h localhost -U postgres -f-Una vez que la consulta se haya ejecutado, verás los siguientes resultados:
CREATE DATABASE You are now connected to database "sampledb" as user "postgres". CREATE TABLE INSERT 0 3Ejecuta el siguiente comando
psqlpara verificar si la tabla llamada users se ha poblado en la base de datossampledbo no.$ docker exec -it postgres psql -h localhost -U postgres sampledbPuedes ejecutar
\len la consola depsqlpara listar todas las bases de datos en el servidor de Postgres.sampledb=# \l List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges -----------+----------+----------+------------+------------+------------+-----------------+----------------------- postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | sampledb | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres (4 rows)Para recuperar todos los datos de la tabla users, ingresa la siguiente consulta:
sampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | [email protected] 2 | Beta | [email protected] 3 | Gamma | [email protected] (3 rows)Usa
\qo\quitpara salir de la consola interactiva de Postgres.
Preinicializar la base de datos montando un script SQL
En Docker, el montaje (mounting) se refiere a hacer que los archivos o directorios del sistema host sean accesibles dentro de un contenedor. Esto te ayuda a compartir datos o archivos de configuración entre el host y el contenedor, permitiendo una mayor flexibilidad y persistencia.
Una vez que has aprendido a iniciar Postgres y a preinicializar la base de datos usando un script SQL, es hora de aprender a montar un archivo SQL directamente en el directorio de inicialización de los contenedores de Postgres (/docker-entrypoint-initdb.d). El directorio /docker-entrypoint-initdb.d es una carpeta especial en los contenedores Docker de PostgreSQL que se utiliza para inicializar la base de datos cuando el contenedor se inicia por primera vez.
Asegúrate de detener cualquier contenedor de Postgres que esté en ejecución (junto con sus volúmenes) para evitar conflictos de puertos antes de seguir los pasos:
$ docker container stop postgres
Modifica
seed.sqlcon las siguientes entradas:CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) UNIQUE ); INSERT INTO users (name, email) VALUES ('Alpha', '[email protected]'), ('Beta', '[email protected]'), ('Gamma', '[email protected]') ON CONFLICT (email) DO NOTHING;Crea un archivo de texto llamado
Dockerfiley copia el siguiente contenido.# syntax=docker/dockerfile:1 FROM postgres:18 COPY seed.sql /docker-entrypoint-initdb.d/Este Dockerfile copia el script
seed.sqldirectamente en el directorio de inicialización del contenedor de PostgreSQL.Usar Docker Compose.
El uso de Docker Compose facilita aún más la administración y el despliegue del contenedor de PostgreSQL con la base de datos inicializada. Este archivo compose.yml define un servicio de Postgres llamado
dbque utiliza la última imagen de Postgres, el cual configura una base de datos con el nombresampledb, junto con un usuariopostgresy la contraseñamysecretpassword.services: db: build: context: . dockerfile: Dockerfile container_name: my_postgres_db environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: mysecretpassword POSTGRES_DB: sampledb ports: - "5432:5432" volumes: - data_sql:/var/lib/postgresql # Almacenamiento persistente de datos volumes: data_sql:Mapea el puerto
5432del host al5432del contenedor, lo que te permite acceder a la base de datos Postgres desde fuera del contenedor. También definedata_sqlpara conservar los datos de la base de datos de manera persistente, asegurando que la información no se pierda al detener el contenedor.Cabe destacar que el mapeo de puertos al host solo es necesario si deseas conectarte a la base de datos desde programas no contenedorizados. Si contenedorizas el servicio que se conecta a la base de datos, deberías conectarte a ella a través de una red puente (bridge network) personalizada.
Iniciar el servicio de Compose.
Asumiendo que has colocado el archivo
seed.sqlen el mismo directorio que el Dockerfile, ejecuta el siguiente comando:$ docker compose up -d --buildEs hora de verificar si la tabla
usersse ha poblado con los datos.$ docker exec -it my_postgres_db psql -h localhost -U postgres sampledbsampledb=# SELECT * FROM users; id | name | email ----+-------+------------------- 1 | Alpha | alpha@example.com 2 | Beta | beta@example.com 3 | Gamma | gamma@example.com (3 rows) sampledb=#
Preinicializar la base de datos usando código JavaScript
Una vez que has aprendido a inicializar la base de datos utilizando varios métodos como scripts SQL, montaje de volúmenes, etc., es hora de intentar lograrlo utilizando código JavaScript.
Crea un archivo .env con lo siguiente:
POSTGRES_USER=postgres POSTGRES_DB_HOST=localhost POSTGRES_DB=sampledb POSTGRES_PASSWORD=mysecretpassword POSTGRES_PORT=5432Crea un nuevo archivo JavaScript llamado seed.js con el siguiente contenido:
El siguiente código JavaScript importa el paquete
dotenv, el cual se utiliza para cargar variables de entorno desde un archivo.env. El método.config()lee el archivo.envy establece las variables de entorno como propiedades del objetoprocess.env. Esto te permite almacenar de forma segura información confidencial, como las credenciales de la base de datos, fuera de tu código.Luego, crea una nueva instancia de Pool de la biblioteca pg, la cual proporciona un grupo de conexiones (connection pool) para interacciones eficientes con la base de datos. La función
seedDataestá definida para realizar las operaciones de inicialización de la base de datos. Se llama al final del script para iniciar el proceso de inicialización. El bloque try...catch...finally se utiliza para el manejo de errores.require('dotenv').config(); // Carga variables de entorno desde el archivo .env const { Pool } = require('pg'); // Crea una nueva pool usando variables de entorno const pool = new Pool({ user: process.env.POSTGRES_USER, host: process.env.POSTGRES_DB_HOST, database: process.env.POSTGRES_DB, port: process.env.POSTGRES_PORT, password: process.env.POSTGRES_PASSWORD, }); const seedData = async () => { try { // Elimina la tabla si ya existe (opcional) await pool.query(`DROP TABLE IF EXISTS todos;`); // Crea la tabla con la estructura correcta await pool.query(` CREATE TABLE todos ( id SERIAL PRIMARY KEY, task VARCHAR(255) NOT NULL, completed BOOLEAN DEFAULT false ); ` ); // Inserta datos de inicialización await pool.query(` INSERT INTO todos (task, completed) VALUES ('Watch netflix', false), ('Finish podcast', false), ('Pick up kid', false); `); console.log('Database seeded successfully!'); } catch (err) { console.error('Error seeding the database', err); } finally { pool.end(); } }; // Llama a la función seedData para ejecutar el script seedData();Inicia el proceso de inicialización
$ node seed.jsDeberías ver el siguiente mensaje:
Database seeded successfully!Verifica si la base de datos se ha inicializado correctamente:
$ docker exec -it postgres psql -h localhost -U postgres sampledbsampledb=# SELECT * FROM todos; id | task | completed ----+----------------+----------- 1 | Watch netflix | f 2 | Finish podcast | f 3 | Pick up kid | f (3 rows)
Resumen
La preinicialización de una base de datos con esquema y datos al inicio es esencial para crear un entorno de pruebas coherente y realista, lo que ayuda a identificar problemas al principio del desarrollo y a alinear el trabajo del frontend y el backend. Esta guía te ha proporcionado los conocimientos y los pasos prácticos para lograr la preinicialización mediante varios métodos, incluyendo scripts SQL, integración con Docker y código JavaScript.