Contenido
Tutorial de PostgreSQL en Docker: instalación, conexión, copias de seguridad y actualización
Cambio importante en PostgreSQL 18: a partir de
postgres:18, el directorio de datos de la imagen oficial cambia a/var/lib/postgresql/18/docker. El Volume debe montarse en/var/lib/postgresql. La mayoría de los tutoriales disponibles indican la ruta/var/lib/postgresql/data, que se usaba hasta la versión 17; con la versión 18, el inicio falla. Consulta las pruebas de abajo.
Inicia con un solo comando
$ docker run -d --name pg -e POSTGRES_PASSWORD=secret -p 127.0.0.1:5432:5432 -v pgdata:/var/lib/postgresql --restart unless-stopped postgres:18
1b34d05a195f347c86e431441162b760167a5c04016a528e10342d0199be016d
$ docker logs pg 2>&1 | tail -n 3
2026-10-13 00:53:32.071 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2026-10-13 00:53:32.075 UTC [72] LOG: database system was shut down at 2026-10-13 00:53:31 UTC
2026-10-13 00:53:32.080 UTC [1] LOG: database system is ready to accept connections
$ docker exec pg psql -U postgres -c "SHOW data_directory;"
data_directory
-------------------------------
/var/lib/postgresql/18/docker
(1 row)
| Parámetro | Descripción |
|---|---|
POSTGRES_PASSWORD | Contraseña del superusuario (obligatoria) |
-p 127.0.0.1:5432:5432 | Solo accesible desde la máquina local |
-v pgdata:/var/lib/postgresql | Los datos se guardan en el Volume pgdata. En la versión 18, hay que montar esta ruta |
SHOW data_directory confirma que el directorio de datos real es /var/lib/postgresql/18/docker, dentro de /var/lib/postgresql, que es donde lo hemos montado. El nombre del directorio incluye el número de versión principal, así que los datos de las versiones antigua y nueva pueden coexistir en el mismo Volume durante una actualización futura.
Otras variables de entorno habituales:
| Variable de entorno | Descripción | Valor predeterminado |
|---|---|---|
POSTGRES_USER | Nombre del superusuario | postgres |
POSTGRES_DB | Base de datos predeterminada | Igual que POSTGRES_USER |
PGDATA | Directorio de datos | /var/lib/postgresql/18/docker (versión 18) |
TZ | Zona horaria | UTC |
Al igual que con MySQL, estas variables solo se aplican cuando el directorio de datos está vacío. Cambiar
POSTGRES_PASSWORDdespués no cambia la contraseña existente; usaALTER USER ... PASSWORD '...'para cambiarla.
Prueba: el montaje de la ruta antigua falla en la versión 18
Monta el Volume en /var/lib/postgresql/data, como indican los tutoriales antiguos:
$ docker run -d --name pgold -e POSTGRES_PASSWORD=secret -v pgold:/var/lib/postgresql/data postgres:18
b480eb9c72b29fa99f1ed8df17972e2bfc2d6da4b86c058a36cf21fd63579bfa
$ docker ps -a --filter name=pgold --format "{{.Status}}"
Exited (1) 5 seconds ago
$ docker logs pgold 2>&1 | head -n 12
Error: in 18+, these Docker images are configured to store database data in a
format which is compatible with "pg_ctlcluster" (specifically, using
major-version-specific directory names). This better reflects how
PostgreSQL itself works, and how upgrades are to be performed.
See also https://github.com/docker-library/postgres/pull/1259
Counter to that, there appears to be PostgreSQL data in:
/var/lib/postgresql/data (unused mount/volume)
This is usually the result of upgrading the Docker image without
upgrading the underlying database using "pg_upgrade" (which requires both
El contenedor termina con Exited (1) en unos segundos. El mensaje de error explica que la versión 18 usa directorios cuyos nombres incluyen la versión principal y que encontró un «montaje sin usar» en /var/lib/postgresql/data. Esta comprobación evita que creas que los datos se han guardado cuando, en realidad, están dentro del contenedor y desaparecen al eliminarlo. Basta con cambiar la ruta de montaje a /var/lib/postgresql.
Gestión con Compose
Para un proyecto real, te recomendamos usar Compose. Crea la carpeta pg-demo:
pg-demo/
├── compose.yaml
├── .env
└── initdb/
└── 01-init.sql
.env:
DB_PASSWORD=change-this-password
initdb/01-init.sql (se ejecuta durante la primera inicialización y crea la extensión, la tabla y los datos de ejemplo; el pg_sleep(8) final simula deliberadamente una inicialización lenta, por ejemplo, al importar muchos datos, para observar la comprobación de estado):
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE TABLE products (
id serial PRIMARY KEY,
name text NOT NULL,
price integer NOT NULL
);
INSERT INTO products (name, price) VALUES ('珍珠奶茶', 65), ('鳳梨酥', 45), ('牛肉麵', 180);
-- Simula una inicialización lenta (por ejemplo, al importar muchos datos)
SELECT pg_sleep(8);
compose.yaml:
services:
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: app
TZ: Asia/Taipei
command: ["postgres", "-c", "max_connections=200", "-c", "shared_buffers=256MB"]
ports:
- "127.0.0.1:5432:5432"
volumes:
- pgdata:/var/lib/postgresql
- ./initdb:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app"]
interval: 2s
timeout: 3s
retries: 30
shm_size: 256mb
restart: unless-stopped
volumes:
pgdata:
| Configuración | Descripción |
|---|---|
POSTGRES_USER: app | Cambia el nombre del superusuario a app. Ya no habrá ningún usuario llamado postgres |
command: ["postgres", "-c", ...] | Pasa la configuración de PostgreSQL con -c; no hace falta preparar un archivo de configuración aparte |
pg_isready -h 127.0.0.1 | Herramienta de comprobación integrada de PostgreSQL. Debes añadir -h 127.0.0.1; consulta la prueba más abajo para conocer el motivo |
shm_size: 256mb | La memoria compartida predeterminada de Docker, /dev/shm, es de solo 64 MB. Las consultas más complejas pueden provocar el error could not resize shared memory segment |
$ docker compose up -d --wait
[+] up 3/3
✔ Network pg-demo_default Created 0.0s
✔ Volume pg-demo_pgdata Created 0.0s
✔ Container pg-demo-db-1 Healthy 11.3s
$ docker compose exec db psql -U app -h 127.0.0.1 -c "SELECT * FROM products;"
id | name | price
----+----------+-------
1 | 珍珠奶茶 | 65
2 | 鳳梨酥 | 45
3 | 牛肉麵 | 180
(3 rows)
$ docker compose logs db 2>&1 | grep -E "running /docker-entrypoint-initdb.d|init process complete|listening on IPv4"
db-1 | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01-init.sql
db-1 | PostgreSQL init process complete; ready for start up.
db-1 | 2026-10-13 08:52:58.663 CST [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
$ docker compose exec db psql -U app -c "SHOW max_connections;" -c "SHOW shared_buffers;" -c "SELECT now();"
max_connections
-----------------
200
(1 row)
shared_buffers
----------------
256MB
(1 row)
now
-------------------------------
2026-10-13 08:53:01.293902+08
(1 row)
$ docker compose exec db df -h /dev/shm
Filesystem Size Used Avail Use% Mounted on
shm 256M 1.1M 255M 1% /dev/shm
$ docker compose exec db psql -U app -c "\dx"
List of installed extensions
Name | Version | Default version | Schema | Description
---------+---------+-----------------+------------+-------------------------------------------------------------------
pg_trgm | 1.6 | 1.6 | public | text similarity measurement and index searching based on trigrams
plpgsql | 1.0 | 1.0 | pg_catalog | PL/pgSQL procedural language
(2 rows)
Healthytardó 11.3 segundos, justo el tiempo de la inicialización máspg_sleep(8). En cuanto estuvo listo, la conexión TCP funcionó; todos los datos estaban ahí y el texto chino se veía correctamente.- Los registros muestran que se ejecutó el script de inicialización y que el servidor empezó a escuchar en
0.0.0.0:5432después de terminar la inicialización. max_connectionses 200 yshared_bufferses 256MB: los parámetros decommandsurtieron efecto.now()muestra la zona horaria+08./dev/shmtiene 256M:shm_sizesurtió efecto.\dxmuestra las extensiones instaladas; el script de inicialización ya creópg_trgm.
Trampa de la comprobación de estado: sin -h, pg_isready indica healthy demasiado pronto
Una forma habitual de escribirlo en Internet es pg_isready -U app -d app (sin -h). Probamos a cambiarlo por esa opción:
$ docker compose up -d --wait
[+] up 3/3
✔ Network pg-demo_default Created 0.0s
✔ Volume pg-demo_pgdata Created 0.0s
✔ Container pg-demo-db-1 Healthy 3.2s
$ docker compose exec db psql -U app -h 127.0.0.1 -c "SELECT count(*) FROM products;"
psql: error: connection to server at "127.0.0.1", port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
$ docker compose logs db 2>&1 | grep -E "pg_sleep|init process complete|listening on IPv4"
Solo habían pasado 3.2 segundos cuando indicó Healthy, pero la conexión TCP devolvió Connection refused.
El motivo es el mismo que en MySQL: durante la inicialización, el script de arranque inicia primero un servidor temporal que solo acepta conexiones por socket Unix para ejecutar los scripts de initdb. Si no añades -h, pg_isready usa el socket y, por tanto, indica que se puede conectar antes de que termine la inicialización. La aplicación que depende de él (depends_on con condition: service_healthy) se inicia en ese momento, pero la conexión TCP falla. Añade -h 127.0.0.1 para forzar la conexión TCP y esperar a que se inicie el servidor definitivo.
Conexión y psql
Operar con psql
El contenedor incluye el cliente psql. Para usarlo de forma interactiva, ejecuta docker compose exec db psql -U app (si es un contenedor independiente, ejecuta docker exec -it pg psql -U postgres); cuando aparezca el indicador app=#, introduce SQL o los comandos de abajo. También puedes ejecutar un comando directamente con -c:
$ docker compose exec db psql -U app -c "SELECT version();"
version
--------------------------------------------------------------------------------------------------------------------
PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
(1 row)
$ docker compose exec db psql -U app -c "\l"
List of databases
Name | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges
-----------+-------+----------+-----------------+------------+------------+--------+-----------+-------------------
app | app | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |
postgres | app | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |
template0 | app | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/app +
| | | | | | | | app=CTc/app
template1 | app | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/app +
| | | | | | | | app=CTc/app
(4 rows)
$ docker compose exec db psql -U app -c "\dt"
List of tables
Schema | Name | Type | Owner
--------+----------+-------+-------
public | products | table | app
(1 row)
$ docker compose exec db psql -U app -c "\d products"
Table "public.products"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+--------------------------------------
id | integer | | not null | nextval('products_id_seq'::regclass)
name | text | | not null |
price | integer | | not null |
Indexes:
"products_pkey" PRIMARY KEY, btree (id)
$ docker compose exec db psql -U app -c "\du"
List of roles
Role name | Attributes
-----------+------------------------------------------------------------
app | Superuser, Create role, Create DB, Replication, Bypass RLS
| Comando | Función |
|---|---|
\l | Lista las bases de datos |
\c nombre | Cambia de base de datos |
\dt | Lista las tablas |
\d tabla | Muestra la estructura de la tabla |
\du | Lista los usuarios (roles) |
\dx | Lista las extensiones instaladas |
\q | Salir |
\du muestra que app es Superuser, y en \l el Owner de todas las bases de datos también es app: al establecer POSTGRES_USER, este reemplaza al valor predeterminado postgres.
Por qué no hace falta introducir una contraseña dentro del contenedor
Los comandos psql de arriba no requieren contraseña. Consulta pg_hba.conf (las reglas de autenticación de conexiones de PostgreSQL) en el directorio de datos:
$ docker compose exec db grep -v "^#" /var/lib/postgresql/18/docker/pg_hba.conf | grep -v "^$"
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
host all all all scram-sha-256
$ docker run --rm --network pg-demo_default -e PGPASSWORD=wrong postgres:18 psql -h db -U app -c "SELECT 1;"
psql: error: connection to server at "db" (172.19.0.2), port 5432 failed: FATAL: password authentication failed for user "app"
$ docker run --rm --network pg-demo_default -e PGPASSWORD=change-this-password postgres:18 psql -h db -U app -c "SELECT current_user, inet_server_addr();"
current_user | inet_server_addr
--------------+------------------
app | 172.19.0.2
(1 row)
- Configuración de la imagen oficial: las conexiones dentro del contenedor (socket Unix,
127.0.0.1,::1) usantrust, por lo que no se comprueba la contraseña. - Las conexiones desde otros orígenes (la última línea
host all all all) usan autenticación por contraseñascram-sha-256. - Si te conectas a
dbdesde otro contenedor de la misma red Compose, una contraseña incorrecta producepassword authentication failed; solo puedes conectarte con la contraseña correcta.
Por eso, cualquier persona que pueda acceder al contenedor puede operar directamente la base de datos. Esta es también la razón por la que debes proteger los permisos de Docker (consulta Seguridad de Docker). Al conectarte desde el host a través de un puerto publicado con -p, la IP de origen es la puerta de enlace de la red Docker, por lo que también necesitas una contraseña.
Conectarse desde el host y desde otros contenedores
postgres://app:contraseña@127.0.0.1:5432/app # Desde el host (herramienta GUI, aplicación)
postgres://app:contraseña@db:5432/app # Desde otro servicio del mismo proyecto Compose
Errores de conexión habituales
$ docker compose exec db psql -c "SELECT 1;"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
$ docker compose exec db psql -U postgres -c "SELECT 1;"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "postgres" does not exist
$ docker compose exec db psql -U app -d shop -c "SELECT 1;"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "shop" does not exist
$ docker compose exec -e PGPASSWORD=wrong db psql -h 127.0.0.1 -U app -c "SELECT 1;"
?column?
----------
1
(1 row)
$ docker compose exec db psql -U app -h 127.0.0.1 -p 5433 -c "SELECT 1;"
psql: error: connection to server at "127.0.0.1", port 5433 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
| Error | Causa |
|---|---|
role "root" does not exist | No se añadió -U a psql, que usa por defecto el nombre del usuario actual del sistema (dentro del contenedor es root) |
role "postgres" does not exist | Se estableció POSTGRES_USER, por lo que el usuario predeterminado postgres no existe |
database "shop" does not exist | POSTGRES_DB solo crea una base de datos durante la inicialización; debes ejecutar CREATE DATABASE para crear las demás |
Connection refused | El puerto es incorrecto, la base de datos aún no ha terminado de iniciarse o te has conectado al host equivocado |
password authentication failed | La contraseña es incorrecta o el Volume se inicializó con otra contraseña |
Fíjate en el cuarto comando: dentro del contenedor, la conexión a 127.0.0.1 se realizó correctamente incluso con una contraseña incorrecta. Esa es la regla trust que se explicó arriba.
Copia de seguridad y restauración
$ docker compose exec -T db pg_dump -U app app > app.sql
$ ls -lh app.sql && grep -E "^CREATE (TABLE|EXTENSION)" app.sql
-rw-r--r-- 1 root root 2.3K Oct 13 00:53 app.sql
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
CREATE TABLE public.products (
$ docker compose exec -T db pg_dump -U app -Fc app > app.dump
$ ls -lh app.dump
-rw-r--r-- 1 root root 3.1K Oct 13 00:53 app.dump
$ docker compose exec db psql -U app -c "DROP TABLE products;"
DROP TABLE
$ docker compose exec -T db pg_restore -U app -d app --clean --if-exists < app.dump
$ docker compose exec db psql -U app -c "SELECT count(*) FROM products;"
count
-------
3
(1 row)
$ rm app.sql app.dump
| Comando | Descripción |
|---|---|
pg_dump app > app.sql | Exporta como texto SQL sin formato, que puedes leer directamente e importar con psql |
pg_dump -Fc app > app.dump | Formato personalizado comprimido; se restaura con pg_restore y permite elegir qué tablas restaurar |
pg_restore --clean --if-exists | Elimina los objetos existentes antes de restaurar para evitar duplicados |
exec -T | exec de Compose asigna un TTY de forma predeterminada; añade -T para desactivarlo al usar redirecciones |
La copia de seguridad incluye CREATE EXTENSION, por lo que la extensión también se crea al restaurar en una base de datos nueva. Como este ejemplo contiene pocos datos, el formato personalizado (3.1K) ocupa más que el texto sin formato (2.3K); con más datos, el formato personalizado suele ocupar mucho menos.
Otros comandos habituales:
# Copia de seguridad de todas las bases de datos y roles (usuarios y contraseñas)
docker compose exec -T db pg_dumpall -U app > all.sql
# Restaurar texto SQL sin formato
docker compose exec -T db psql -U app -d app < app.sql
Puedes usar cron con los comandos anteriores para hacer copias de seguridad periódicas y copiar los archivos a otro equipo o a un almacenamiento en la nube.
Copia de seguridad y restauración en Windows
PowerShell no admite <, y > en Windows PowerShell 5.1 cambia la codificación del archivo; además, las copias binarias de -Fc se dañan directamente. En su lugar, genera el archivo dentro del contenedor con pg_dump -f y cópialo con docker compose cp. Este método funciona en todos los sistemas:
# Copia de seguridad
docker compose exec db pg_dump -U app -Fc -f /tmp/app.dump app
docker compose cp db:/tmp/app.dump app.dump
# Restauración
docker compose cp app.dump db:/tmp/restore.dump
docker compose exec db pg_restore -U app -d app --clean --if-exists /tmp/restore.dump
Estos comandos no usan $(pwd), < ni >; puedes ejecutarlos directamente en bash, PowerShell y CMD. Prueba realizada (crear una tabla, hacer una copia de seguridad, eliminarla y restaurarla):
$ docker compose exec db psql -U app -c 'CREATE TABLE t (id int); INSERT INTO t VALUES (1),(2);'
CREATE TABLE
INSERT 0 2
$ docker compose exec db pg_dump -U app -Fc -f /tmp/app.dump app
$ docker compose cp db:/tmp/app.dump app.dump
pgwin-db-1 Copying pgwin-db-1:/tmp/app.dump to app.dump
pgwin-db-1 Copied pgwin-db-1:/tmp/app.dump to app.dump
$ ls -l app.dump
-rw-rw-rw- 1 root root 1251 Oct 13 05:30 app.dump
$ docker compose exec db psql -U app -c 'DROP TABLE t;'
DROP TABLE
$ docker compose cp app.dump db:/tmp/restore.dump
pgwin-db-1 Copying app.dump to pgwin-db-1:/tmp/restore.dump
pgwin-db-1 Copied app.dump to pgwin-db-1:/tmp/restore.dump
$ docker compose exec db pg_restore -U app -d app /tmp/restore.dump
$ docker compose exec db psql -U app -c 'SELECT count(*) FROM t;'
count
-------
2
(1 row)
Actualización de versión principal (por ejemplo, de 16 a 18)
Para una actualización menor (por ejemplo, de 18.5 a 18.6), basta con descargar la nueva imagen y volver a crear el contenedor. Las actualizaciones principales son distintas: los formatos de los archivos de datos no son compatibles entre las distintas versiones principales de PostgreSQL.
Primero, crea algunos datos con la versión 16:
$ docker run -d --name pg16 -e POSTGRES_PASSWORD=secret -v pg16data:/var/lib/postgresql/data postgres:16
20691764a98828d24c958eaaa71e83c08ebff29b984350ff7f6782ba8d74b4ca
$ docker exec pg16 psql -U postgres -c "CREATE TABLE notes (id serial PRIMARY KEY, body text); INSERT INTO notes (body) VALUES ('written by 16');"
CREATE TABLE
INSERT 0 1
$ docker stop pg16
pg16
Cambiar directamente la imagen falla
Abre con postgres:18 los datos de la versión 16 (aquí se usa PGDATA para especificar la ruta anterior y simular un cambio directo de la etiqueta de 16 a 18):
$ docker run --name pg18 -e POSTGRES_PASSWORD=secret -e PGDATA=/var/lib/postgresql/data -v pg16data:/var/lib/postgresql/data postgres:18 2>&1 | tail -n 3
2026-10-13 00:54:09.740 UTC [1] FATAL: database files are incompatible with server
2026-10-13 00:54:09.740 UTC [1] DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 18.6 (Debian 18.6-1.pgdg13+2).
$ docker rm pg18
pg18
database files are incompatible with server: el directorio de datos se inicializó con la versión 16 y la versión 18.6 no puede usarlo.
Exportar e importar
La forma más sencilla y segura es exportar todos los datos con pg_dumpall de la versión anterior y luego importarlos en un volumen nuevo de la versión nueva.
$ docker start pg16
pg16
$ docker exec pg16 pg_dumpall -U postgres > upgrade.sql && ls -lh upgrade.sql
-rw-r--r-- 1 root root 3.4K Oct 13 00:54 upgrade.sql
$ docker run -d --name pg18 -e POSTGRES_PASSWORD=secret -v pg18data:/var/lib/postgresql postgres:18
ec651837b76a0c9cc8b2468ec5a2ff4002334dcf015514ef94490a6c38cfe73d
$ docker exec -i pg18 psql -U postgres -q < upgrade.sql
ERROR: role "postgres" already exists
set_config
------------
(1 row)
set_config
------------
(1 row)
setval
--------
1
(1 row)
$ docker exec pg18 psql -U postgres -c "SHOW server_version;" -c "SELECT * FROM notes;"
server_version
-------------------------------
18.6 (Debian 18.6-1.pgdg13+2)
(1 row)
id | body
----+---------------
1 | written by 16
(1 row)
$ rm upgrade.sql
- Puedes ignorar el error
ERROR: role "postgres" already existsdurante la importación: el nuevo contenedor de la versión 18 ya creó el usuariopostgresy la salida depg_dumpallintenta crearlo otra vez. - Por último, comprueba que la versión sea 18.6 y que sigan presentes los datos
written by 16escritos con la versión 16. - Ten en cuenta que el volumen del nuevo contenedor está montado en
/var/lib/postgresql(la nueva ruta de la versión 18).
Cuando hayas confirmado que los datos y la aplicación funcionan correctamente, elimina el contenedor y el volumen antiguos. Si tienes muchos datos y no puedes aceptar una interrupción prolongada, puedes investigar pg_upgrade o la replicación lógica (logical replication), aunque los pasos son mucho más complejos; ensáyalos primero en un entorno de pruebas.
Resumen
- El volumen de PostgreSQL 18 se monta en
/var/lib/postgresql. - Para la comprobación de estado, usa
pg_isready -h 127.0.0.1. - Las conexiones dentro del contenedor usan trust; las conexiones externas requieren una contraseña.
- Para actualizar a una versión principal: exporta con
pg_dumpallde la versión anterior e importa en un volumen nuevo de la versión nueva.
Ejercicios
Ejercicio 1: Usa psql para crear una tabla notes en la base de datos app y luego comprueba el resultado con \dt.
Respuesta
docker compose exec db psql -U app -c "CREATE TABLE notes (id serial PRIMARY KEY, body text);"
docker compose exec db psql -U app -c "\dt"
Ejercicio 2: ¿Qué diferencia hay entre una copia de seguridad en formato personalizado (-Fc) y una en SQL de texto sin formato?
Respuesta
El formato personalizado está comprimido. Para restaurarlo, necesitas pg_restore, que permite restaurar solo algunas tablas. El texto sin formato se puede leer directamente e importar con psql.
Preguntas frecuentes
¿postgres:18 se cierra nada más iniciarse?
La versión 18 requiere montar /var/lib/postgresql. Si se monta la ruta antigua /var/lib/postgresql/data, se cierra al detectar un directorio incompatible. Consulta las pruebas de este capítulo.
¿Cómo se hace una actualización de versión secundaria (18.5 → 18.6)?
Basta con descargar la nueva imagen y recrear el contenedor: docker compose pull db && docker compose up -d db. Solo hace falta exportar e importar para las versiones principales.
¿Falla pg_restore en Windows?
PowerShell no admite < y > en la versión 5.1 puede dañar las copias binarias. Usa pg_dump -f para crear el archivo dentro del contenedor y luego cópialo con docker compose cp. Este capítulo incluye los comandos.
Actualizado 14 de octubre de 2026