🗄️ Guía de Aula Invertida
— vistas

Docker para Bases de Datos

Hasta ahora corriste PostgreSQL dentro del navegador. Para trabajar en serio necesitás el motor de verdad en tu máquina, sin instalarlo a mano y sin ensuciar tu sistema. Con Docker levantás PostgreSQL y MongoDB con un comando, los borrás sin dejar rastro y los reproducís idénticos en cualquier computadora.

RC
Ing. Roy Carrasco
Facultad de Ingeniería de Sistemas · UAB

Bienvenido

En las guías anteriores escribiste SQL contra un PostgreSQL que vivía dentro de tu navegador. Sirve para aprender, pero un proyecto real necesita un servidor de base de datos que arranque, guarde datos en disco y acepte conexiones desde tu aplicación. Docker te da eso sin instalar el motor directamente en tu sistema operativo.

Objetivo del módulo

Al finalizar esta guía sabrás levantar PostgreSQL y MongoDB con docker run, configurarlos con variables de entorno, hacer que sus datos sobrevivan con volúmenes, conectarte mediante puertos, y describir los dos motores juntos en un archivo docker-compose.yml.

⚠️ Esta guía no ejecuta Docker en el navegador

A diferencia de los talleres, acá los comandos los corrés vos, en tu propia terminal. Para eso necesitás Docker instalado: Docker Desktop en Windows o macOS (en Windows usa WSL 2), o Docker Engine en Linux. Comprobalo con docker --version y docker compose version. Los bloques de código de esta guía sí se pueden seleccionar y copiar.

📝 Actividades de este módulo

Encontrarás actividades cortas y autocorregibles repartidas por la guía, un armador de comandos interactivo para experimentar sin calificar, y una sección de escenarios de fallas reales donde tenés que decidir qué pasó antes de ver la respuesta.

📦 Aislá

Cada motor corre en su propio contenedor, sin tocar el resto de tu computadora.

💾 Persistí

Los volúmenes deciden si tus datos sobreviven cuando el contenedor desaparece.

🔌 Conectá

Puertos y variables de entorno son la puerta de entrada y la configuración de cada base de datos.

Imágenes y contenedores

Instalar PostgreSQL directamente en tu sistema tiene costos escondidos: una sola versión a la vez, servicios que arrancan solos, y una desinstalación que casi nunca deja todo limpio. Un contenedor evita todo eso.

ConceptoQué es
ImagenUna plantilla de solo lectura con el programa y todo lo que necesita (por ejemplo postgres:16). Se descarga una vez desde un registro como Docker Hub.
ContenedorUna instancia en ejecución de una imagen, con su propio sistema de archivos y su propia red. De una misma imagen podés crear varios contenedores.
VolumenUn espacio de almacenamiento que vive fuera del contenedor. Es lo que permite que los datos sobrevivan a su borrado.
Etiqueta (tag)La versión de la imagen después de los dos puntos: postgres:16. Sin etiqueta Docker usa latest, y una actualización silenciosa puede romperte el proyecto.
Fijá siempre la versión

Escribí postgres:16 y no solo postgres. Así todo el equipo, y vos dentro de seis meses, levantan exactamente el mismo motor. Un salto de versión mayor puede cambiar el formato de los datos en disco.

Selección múltiple

Corrés docker run tres veces con la imagen postgres:16, cada vez con un nombre distinto. ¿Qué obtenés?

docker run con PostgreSQL

Este es el comando mínimo para tener un PostgreSQL real escuchando en tu máquina:

Terminal
docker run -d --name pg-uab \
  -e POSTGRES_PASSWORD=cambiame123 \
  -p 5432:5432 \
  postgres:16

La primera vez, Docker descarga la imagen (puede tardar un par de minutos). Después crea el contenedor y lo deja corriendo. Cada parte del comando cumple un rol:

ParteQué hace
-dModo detached: el contenedor corre en segundo plano y te devuelve la terminal.
--name pg-uabLe pone un nombre que vos elegís. Sin esto Docker inventa uno al azar.
-e VARIABLE=valorDefine una variable de entorno dentro del contenedor: así se configura la imagen.
-p 5432:5432Publica un puerto: conecta el puerto de tu máquina con el del contenedor.
postgres:16La imagen y su versión. Va siempre al final.

Para comprobar que está vivo y entrar a un psql dentro del contenedor:

Terminal
docker ps                        # contenedores en ejecución
docker logs pg-uab               # mensajes del motor al arrancar
docker exec -it pg-uab psql -U postgres

Dentro de psql ya podés correr CREATE TABLE, INSERT y todo lo que practicaste en las guías anteriores, pero ahora sobre un PostgreSQL de verdad. Salís con \q.

Clasificación

Clasifica cada necesidad según el tipo de opción de docker run que la resuelve.

Que la base de datos siga existiendo después de borrar el contenedor.
Definir la contraseña del superusuario al crear el contenedor.
Poder conectarte desde DBeaver, instalado en tu propia máquina.
Guardar los archivos de datos en una carpeta de tu proyecto.

Variables de entorno

Las imágenes oficiales no traen un archivo de configuración para editar: se configuran con variables de entorno que definís con -e. Estas son las de PostgreSQL:

VariableEfecto
POSTGRES_PASSWORDObligatoria. Contraseña del superusuario. Sin ella el contenedor se detiene al arrancar.
POSTGRES_USERNombre del superusuario. Si no la definís, es postgres.
POSTGRES_DBBase de datos que se crea al iniciar. Si no la definís, usa el nombre del usuario.
Terminal
docker run -d --name pg-uab \
  -e POSTGRES_USER=roy \
  -e POSTGRES_PASSWORD=cambiame123 \
  -e POSTGRES_DB=tienda \
  -p 5432:5432 \
  postgres:16
Las variables se leen una sola vez

PostgreSQL usa POSTGRES_USER, POSTGRES_PASSWORD y POSTGRES_DB únicamente cuando inicializa un directorio de datos vacío. Si después cambiás la contraseña en el comando pero el volumen ya tiene datos, el motor ignora el valor nuevo y sigue con el anterior. Es la causa de confusión más frecuente con Docker y bases de datos.

La contraseña no va en el repositorio

Escribirla en el comando la deja en el historial de tu terminal. Escribirla en un docker-compose.yml versionado la publica junto con el código. La práctica correcta es guardarla en un archivo .env que Git ignora (línea .env en .gitignore) y pasarla con --env-file .env o dejar que Compose la lea. Lo vas a ver en la sección de docker-compose.

Completar

Sobre la configuración de la imagen de PostgreSQL:

1. Si arrancás el contenedor sin definir la contraseña del superusuario, el resultado es que .

2. Para que la contraseña no quede escrita en el código, lo más adecuado es guardarla en .

Volúmenes: que los datos sobrevivan

Un contenedor es desechable por diseño. Todo lo que escribe dentro de su propio sistema de archivos desaparece con él. Para una base de datos eso es un desastre, salvo que guardes los datos en un volumen.

Terminal
docker run -d --name pg-uab \
  -e POSTGRES_PASSWORD=cambiame123 \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

-v pgdata:/var/lib/postgresql/data significa: "guardá lo que el contenedor escribe en /var/lib/postgresql/data (el directorio de datos de PostgreSQL) dentro del volumen llamado pgdata". Si borrás el contenedor y creás otro con el mismo -v, la base de datos reaparece intacta.

OpciónSintaxisCuándo conviene
Sin volumen(nada)Pruebas descartables. Al borrar el contenedor, la base de datos queda huérfana y el próximo arranca vacío.
Volumen con nombre-v pgdata:/rutaLa opción recomendada para bases de datos. Docker lo administra y funciona igual en todos los sistemas.
Carpeta local (bind mount)-v ./datos:/rutaCuando querés ver los archivos desde tu máquina, por ejemplo para scripts. En Windows y macOS con Postgres puede dar problemas de permisos.
Sin volumen, los datos no se pierden: se pierde el acceso a ellos

La imagen de PostgreSQL crea un volumen anónimo automáticamente aunque no lo pidas. Al borrar el contenedor, esos datos quedan en un volumen con nombre aleatorio al que nadie apunta, y el contenedor nuevo arranca con una base vacía. Por eso conviene siempre nombrar el volumen.

Ojo con la versión de la imagen

Este ejemplo usa postgres:16. Desde PostgreSQL 18 la imagen oficial cambió el punto de montaje recomendado. Si usás otra versión mayor, revisá la documentación de la imagen en Docker Hub antes de copiar la ruta.

Para administrar volúmenes:

Terminal
docker volume ls                 # lista los volúmenes
docker volume inspect pgdata     # dónde vive y desde cuándo existe
docker volume rm pgdata          # BORRA los datos para siempre
Emparejamiento

Une cada comando con su efecto sobre los datos guardados en un volumen con nombre.

Selección múltiple

Creaste una base con -v pgdata:/var/lib/postgresql/data, cargaste datos y ejecutaste docker rm -f pg-uab. ¿Cómo recuperás la base?

Puertos y conexión

Un contenedor tiene su propia red aislada. PostgreSQL escucha en el puerto 5432 adentro, pero tu máquina no lo ve hasta que lo publicás con -p.

Sintaxis
-p PUERTO_DE_TU_MAQUINA:PUERTO_DEL_CONTENEDOR

El puerto de la derecha lo fija el motor: 5432 para PostgreSQL, 27017 para MongoDB. El de la izquierda lo elegís vos. Si ya tenés otro PostgreSQL instalado en tu máquina usando el 5432, Docker se queja con port is already allocated. La solución es cambiar solo el lado izquierdo:

Terminal
docker run -d --name pg-uab \
  -e POSTGRES_PASSWORD=cambiame123 \
  -p 5433:5432 \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# desde tu máquina ahora te conectás al 5433
psql -h localhost -p 5433 -U postgres

Una aplicación o herramienta (DBeaver, tu backend) usa una cadena de conexión con esos mismos datos:

Cadenas de conexión
postgresql://postgres:cambiame123@localhost:5433/postgres
mongodb://admin:cambiame123@localhost:27017/?authSource=admin
Publicar un puerto lo expone

-p 5432:5432 escucha en todas las interfaces de tu máquina, y por tanto en tu red local. En una computadora compartida o una red pública conviene limitarlo a tu equipo con -p 127.0.0.1:5432:5432. Y nunca uses una contraseña como postgres o admin en un puerto abierto.

Selección múltiple

Ejecutaste el contenedor con -p 5433:5432. Desde DBeaver, en tu máquina, ¿a qué puerto te conectás?

MongoDB en un contenedor

MongoDB sigue exactamente el mismo patrón: imagen oficial, variables de entorno para el usuario administrador, un puerto y un volumen. Lo único que cambia son los nombres.

Terminal
docker run -d --name mongo-uab \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=cambiame123 \
  -p 27017:27017 \
  -v mongodata:/data/db \
  mongo:7

docker exec -it mongo-uab mongosh -u admin -p cambiame123 --authenticationDatabase admin
PostgreSQLMongoDB
Imagenpostgres:16mongo:7
Puerto estándar543227017
Datos dentro del contenedor/var/lib/postgresql/data/data/db
Contraseña del administradorPOSTGRES_PASSWORDMONGO_INITDB_ROOT_PASSWORD
Cliente en la terminalpsqlmongosh

Con esto ya tenés el entorno listo para las próximas guías: JSON en PostgreSQL y, después, MongoDB de verdad. Y para el proyecto integrador vas a necesitar los dos motores corriendo a la vez, que es justo lo que resuelve la siguiente sección.

Emparejamiento

Une cada dato con lo que representa en la configuración de los contenedores.

docker-compose: los dos motores juntos

Dos motores con sus puertos, variables y volúmenes son dos comandos largos que nadie quiere recordar. Docker Compose describe todo en un archivo docker-compose.yml y lo levanta con un solo comando. Además queda dentro del repositorio: quien clone el proyecto tiene el mismo entorno.

docker-compose.yml
services:
  postgres:
    image: postgres:16
    container_name: pg-uab
    environment:
      POSTGRES_USER: roy
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: tienda
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U roy -d tienda"]
      interval: 5s
      retries: 5

  mongo:
    image: mongo:7
    container_name: mongo-uab
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
    ports:
      - "27017:27017"
    volumes:
      - mongodata:/data/db

volumes:
  pgdata:
  mongodata:
.env (junto al docker-compose.yml, ignorado por Git)
POSTGRES_PASSWORD=cambiame123
MONGO_PASSWORD=otra-clave-distinta-456

Compose lee el .env automáticamente y reemplaza cada ${...}. La estructura es la misma que ya conocés, ahora en YAML: image, environment (los -e), ports (los -p) y volumes (los -v). Los volúmenes con nombre se declaran además al final, en el bloque volumes: de nivel superior.

ComandoQué hace
docker compose up -dCrea y arranca todos los servicios en segundo plano.
docker compose psMuestra el estado de los servicios del archivo.
docker compose logs -f postgresSigue en vivo los mensajes de un servicio.
docker compose downDetiene y elimina los contenedores. Los volúmenes se conservan.
docker compose down -vAdemás elimina los volúmenes: borra todos los datos.
Una red compartida, sin configurar nada

Compose pone todos los servicios del archivo en una misma red y cada uno se alcanza por su nombre. Cuando agregues tu aplicación como otro servicio, se conectará al host postgres o mongo, no a localhost: dentro de un contenedor, localhost es ese mismo contenedor. Los puertos publicados con ports sirven para las herramientas que corren en tu máquina.

Scripts de inicialización

Si montás una carpeta con archivos .sql en /docker-entrypoint-initdb.d, PostgreSQL los ejecuta en orden al inicializar. Es la forma de arrancar con las tablas del esquema ya creadas. Como las variables de entorno, corren solo la primera vez, con el directorio de datos vacío.

Completar

Sobre el archivo de Compose de arriba:

1. Para levantar los dos motores juntos, en segundo plano, ejecutás .

2. Para apagar todo pero conservar los datos guardados, ejecutás .

3. Una aplicación que corre como otro servicio de este archivo se conecta a PostgreSQL usando el host .

🧪 Actividad exploratoria · no califica

Armador de comandos

Elegí los motores y las opciones, y mirá cómo cambian al instante el comando docker run y el docker-compose.yml. Los avisos de abajo te dicen qué riesgo introduce cada decisión.

docker run
docker-compose.yml

Cuando algo falla

Casi todos los problemas con bases de datos en Docker caen en un puñado de errores. Reconocerlos por su mensaje te ahorra horas.

Mensaje o síntomaCausa habitual
port is already allocatedOtro programa o contenedor ya usa ese puerto de tu máquina. Cambiá el número de la izquierda de -p.
container name "/pg-uab" is already in useYa existe un contenedor con ese nombre, aunque esté detenido. Borralo con docker rm pg-uab o elegí otro nombre.
Database is uninitialized and superuser password is not specifiedFalta POSTGRES_PASSWORD.
password authentication failedLa contraseña que usás no es la que quedó guardada al inicializar el volumen. Cambiar la variable después no la modifica.
La base de datos aparece vacía después de recrear el contenedorEl contenedor nuevo montó otro volumen (o ninguno). Revisá el -v con docker volume ls.
Selección múltiple

Tu compañera cambió POSTGRES_PASSWORD en el docker-compose.yml y ejecutó docker compose up -d, pero el volumen pgdata ya tenía datos. Al conectarse con la clave nueva recibe password authentication failed. ¿Por qué?

Selección múltiple

Al ejecutar docker run ... -p 5432:5432 ... aparece port is already allocated. Tenés un PostgreSQL instalado en tu PC que no querés apagar. ¿Qué hacés?

Completar

Un equipo trabaja con Compose y volúmenes con nombre. Predecí qué pasa en cada caso:

1. Ejecutan docker compose down al terminar el día y docker compose up -d a la mañana siguiente: las tablas .

2. Ejecutan docker compose down -v y luego up -d: la base de datos .

Actividades de repaso

Un repaso integrador de todo el módulo. Cada actividad se corrige al instante; tu progreso se guarda automáticamente en este navegador.

0 / 0
actividades correctas en toda la guía
Selección múltiple

¿Qué diferencia hay entre una imagen y un contenedor?

Verdadero o falso

Al ejecutar docker rm sobre un contenedor de PostgreSQL cuyo directorio de datos está montado en un volumen con nombre, se borran también los datos del volumen.

Selección múltiple

¿Qué configura la variable MONGO_INITDB_ROOT_USERNAME?

Selección múltiple

Tu aplicación corre como un servicio más del mismo docker-compose.yml que PostgreSQL. ¿Qué host usa en su cadena de conexión?

Selección múltiple

¿Por qué conviene escribir postgres:16 en lugar de solo postgres?

Cheat Sheet

ComandoPara qué sirve
docker run -d --name X -e V=v -p H:C -v vol:/ruta imagen:tagCrea y arranca un contenedor en segundo plano.
docker ps -aLista contenedores, incluidos los detenidos.
docker logs -f XSigue en vivo los mensajes del contenedor.
docker exec -it X psql -U usuarioAbre un cliente dentro del contenedor.
docker stop X / docker start XDetiene o reanuda un contenedor sin perder nada.
docker rm XElimina el contenedor (los volúmenes con nombre quedan).
docker volume ls / rm VLista o elimina volúmenes. rm borra los datos.
docker compose up -d / downLevanta o apaga todos los servicios del archivo.
docker compose down -vApaga y borra también los volúmenes: pierde los datos.
POSTGRES_PASSWORD · MONGO_INITDB_ROOT_PASSWORDContraseñas de administrador; solo se leen al inicializar.

¿Sabías que...?

🐋 El nombre

Docker se lanzó como proyecto de código abierto en 2013. La ballena de su logo carga contenedores sobre el lomo, igual que los barcos de carga que inspiraron el nombre.

⚡ No es una máquina virtual

Un contenedor comparte el núcleo del sistema operativo de tu computadora, por eso arranca en segundos y pesa mucho menos que una máquina virtual completa, que trae su propio sistema operativo.

🧹 Entornos descartables

Como un contenedor se destruye y recrea en segundos, muchos equipos levantan una base de datos limpia para cada ejecución de sus pruebas automáticas y la tiran al terminar.