# Configuración inmediata y persistencia de datos


Esta guía te llevará de cero a un contenedor de PostgreSQL en funcionamiento en menos de cinco minutos, y luego te explicará cómo mantener tus datos seguros a través de los reinicios y eliminaciones de contenedores.

## Descripción general

Ejecutar PostgreSQL en Docker requiere comprender un concepto crítico: los contenedores son efímeros, pero tus datos no deberían serlo. Esta guía cubre:

- Iniciar PostgreSQL con un solo comando
- Comprender por qué los contenedores pierden datos de forma predeterminada
- Configurar volúmenes para almacenamiento persistente
- Traducir tu configuración a Docker Compose

## Inicio rápido (contenedor mínimo viable)

> [!NOTE]
>
> Las [imágenes endurecidas de Docker (DHI, Docker Hardened Images)](https://docs-docker.esdocu.com/dhi/) son imágenes de aplicación y base de contenedor mínimas, seguras y listas para producción mantenidas por Docker. Se recomiendan las DHI siempre que sea posible para una mejor seguridad. Están diseñadas para reducir las vulnerabilidades y simplificar el cumplimiento, disponibles de forma gratuita para todos sin necesidad de suscripción, sin restricciones de uso y sin dependencia del proveedor (vendor lock-in).

Ejecuta PostgreSQL inmediatamente con este único comando:

**Usando DHI**



Debes autenticarte en dhi.io antes de poder extraer imágenes endurecidas de Docker (DHI). Ejecuta `docker login dhi.io` para autenticarte.

```console
docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -d dhi.io/postgres:18
```

**Usando DOI**



```console
$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -d postgres:18
```



### Comprender las banderas (flags)

| Bandera | Propósito |
|------|---------|
| `--rm` | Elimina automáticamente el contenedor cuando se detiene |
| `--name postgres-dev` | Asigna un nombre fácil de recordar en lugar de una cadena aleatoria |
| `-e POSTGRES_PASSWORD=...` | Establece la contraseña del superusuario (requerido) |
| `-p 5432:5432` | Mapea el puerto 5432 del host al puerto 5432 del contenedor |
| `-d` | Ejecuta el contenedor en segundo plano (modo desacoplado o detached) |

Verifica que el contenedor se esté ejecutando:

```console
$ docker ps --filter name=postgres-dev
CONTAINER ID   IMAGE         COMMAND                  STATUS         PORTS                    NAMES
a1b2c3d4e5f6   postgres:18   "docker-entrypoint.s…"   Up 2 seconds   0.0.0.0:5432->5432/tcp   postgres-dev
```

Conéctate usando `psql` desde el interior del contenedor:

```console
$ docker exec -it postgres-dev psql -U postgres
psql (18.0)
Type "help" for help.

postgres=#
```

Ahora tienes una instancia de PostgreSQL en funcionamiento. Pero hay un problema: si detienes este contenedor, tus datos desaparecerán.

## El problema de la persistencia de datos

Los contenedores utilizan un sistema de archivos efímero. Cuando se elimina un contenedor, todo lo que hay dentro de él, incluidos los archivos de tu base de datos, se elimina.

Demuéstralo tú mismo:

**Usando DHI**



```console
$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;"
CREATE DATABASE

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
 testdb    | postgres | UTF8     | libc            | en_US.utf8 | en_US.utf8 |            |           |

$ docker stop postgres-dev
postgres-dev

$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -d dhi.io/postgres:18

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
(sin salida - la base de datos ha desaparecido)
```

**Usando DOI**



```console
$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;"
CREATE DATABASE

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
 testdb    | postgres | UTF8     | libc            | en_US.utf8 | en_US.utf8 |            |           |

$ docker stop postgres-dev
postgres-dev

$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -d postgres:18

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
(sin salida - la base de datos ha desaparecido)
```



Tu base de datos `testdb` desapareció porque el nuevo contenedor comenzó con un sistema de archivos limpio. Este es el comportamiento esperado, y es exactamente por eso que existen los volúmenes.

## Volúmenes con nombre

Los volúmenes con nombre son ubicaciones de almacenamiento gestionadas por Docker que persisten de forma independiente a los contenedores. Docker gestiona la ubicación en el sistema de archivos, los permisos y el ciclo de vida.

Crea un contenedor con un volumen con nombre:

**Usando DHI**



Debes autenticarte en dhi.io antes de poder extraer imágenes endurecidas de Docker (DHI). Ejecuta `docker login dhi.io` para autenticarte.

```console
$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v postgres_data:/var/lib/postgresql \
  -d dhi.io/postgres:18
```

**Usando DOI**



```console
$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v postgres_data:/var/lib/postgresql \
  -d postgres:18
```




La bandera `-v postgres_data:/var/lib/postgresql` monta un volumen con nombre llamado `postgres_data` en el directorio de datos de PostgreSQL. Si el volumen no existe, Docker lo crea automáticamente.

> [!NOTE]
>
> PostgreSQL 18+ almacena los datos en un subdirectorio específico de la versión bajo `/var/lib/postgresql`. Montar a este nivel (en lugar de `/var/lib/postgresql/data`) facilita las actualizaciones posteriores utilizando `pg_upgrade --link`.

### Verificar la persistencia de datos

Para verificar la persistencia de datos, repite la prueba anterior, pero esta vez con el volumen con nombre adjunto.

**Usando DHI**



```console
$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;"
CREATE DATABASE

$ docker stop postgres-dev
postgres-dev

$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v postgres_data:/var/lib/postgresql \
  -d dhi.io/postgres:18

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
 testdb    | postgres | UTF8     | libc            | en_US.utf8 | en_US.utf8 |            |           |
```

**Usando DOI**



```console
$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;"
CREATE DATABASE

$ docker stop postgres-dev
postgres-dev

$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v postgres_data:/var/lib/postgresql \
  -d postgres:18

$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb
 testdb    | postgres | UTF8     | libc            | en_US.utf8 | en_US.utf8 |            |           |
```



Si ves `testdb` en la salida, la persistencia funciona: la base de datos sobrevivió porque el volumen preservó el directorio de datos.

### Gestionar volúmenes

Listar todos los volúmenes:

```console
$ docker volume ls --filter name=postgres_data
DRIVER    VOLUME NAME
local     postgres_data
```

Inspecciona un volumen para ver sus detalles:

```console
$ docker volume inspect postgres_data
[
    {
        "CreatedAt": "2025-01-05T10:30:00Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/postgres_data/_data",
        "Name": "postgres_data",
        "Options": null,
        "Scope": "local"
    }
]
```

Elimina un volumen no utilizado (advertencia: esto elimina todos los datos):

```console
$ docker volume rm postgres_data
```

## Montajes de tipo bind (alternativa)

Los montajes de tipo bind (bind mounts) mapean un directorio específico del host a una ruta del contenedor. A diferencia de los volúmenes con nombre, controlas exactamente dónde residen los datos en el sistema de archivos del host.

Crea un directorio en tu máquina host para almacenar los datos de Postgres.

**Usando DHI**



```console
mkdir -p ~/postgres-data && sudo chown -R 999:999 ~/postgres-data
```

Ejecuta Postgres usando un montaje bind.

```console
docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v ~/postgres-data:/var/lib/postgresql \
  -d dhi.io/postgres:18
```

**Usando DOI**



```console
$ mkdir -p ~/postgres-data
```

Ejecuta Postgres usando un montaje bind.

```console
$ docker run --rm --name postgres-dev \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -v ~/postgres-data:/var/lib/postgresql \
  -d postgres:18
```



### Cuándo usar montajes bind

Los montajes bind son útiles cuando necesitas acceso directo del sistema de archivos al directorio de datos para scripts de respaldo que leen archivos directamente, al integrarse con herramientas de monitoreo a nivel de host, o cuando existen requisitos de permisos específicos. Para la mayoría de los escenarios de desarrollo y producción, los volúmenes con nombre son más simples y menos propensos a errores.

### Problemas comunes de los montajes bind

Los errores de permisos son el problema más frecuente con los montajes bind. PostgreSQL se ejecuta como el usuario `postgres` (UID 999) dentro del contenedor. Si el directorio de tu host tiene permisos restrictivos, el contenedor no se iniciará.

Verifica los registros (logs) si el contenedor se cierra inmediatamente:

```console
$ docker logs postgres-dev
```

## Configuración de Docker Compose

Docker Compose captura toda tu configuración en un archivo, lo que hace que las configuraciones sean reproducibles y más fáciles de gestionar a medida que crece la complejidad.

Crea un archivo `compose.yaml`:

```yaml
services:
  db:
    image: postgres:18
    container_name: postgres-dev
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql

volumes:
  postgres_data:
```

Inicia la base de datos:

```console
$ docker compose up -d
```

Detén y elimina los contenedores (el volumen persiste):

```console
$ docker compose down
```

Alternativamente, puedes detener, eliminar los contenedores y borrar el volumen:

```console
$ docker compose down -v
```

Este archivo de Compose se convierte en la base para agregar scripts de inicialización, ajuste de rendimiento y servicios complementarios cubiertos en las guías siguientes.

### Referencia de variables de entorno

La imagen oficial de PostgreSQL admite estas variables de entorno:

| Variable | Requerida | Descripción |
|----------|----------|-------------|
| `POSTGRES_PASSWORD` | Sí | Contraseña del superusuario |
| `POSTGRES_USER` | No | Nombre del superusuario (predeterminado: `postgres`) |
| `POSTGRES_DB` | No | Nombre de la base de datos predeterminada (predeterminado: el valor de `POSTGRES_USER`) |

## Pasos siguientes

Con el almacenamiento persistente configurado, estás listo para personalizar aún más PostgreSQL. El siguiente capítulo de la guía cubre:

- Creación automatizada de esquemas con scripts de inicialización
- Ajuste de rendimiento para cargas de trabajo contenedorizadas
- Configuración de zona horaria e idioma (locale)
