Saltar al contenido

lección 6

Volúmenes y redes: persistir datos y comunicar contenedores

Por qué los datos desaparecen al parar un contenedor, volumes para persistir, networks para comunicar servicios.

50 min

Imagina esto: levantas PostgreSQL con Docker, creas tablas, insertas 10.000 filas de datos de ventas del último mes. Todo perfecto. Luego haces docker compose down y... tus datos han DESAPARECIDO. Completamente. Cuando vuelves a hacer docker compose up, PostgreSQL arranca limpio como el primer día. ¿Qué ha pasado? Bienvenido al concepto más importante (y más doloroso de aprender) de Docker: la EFÍMERA naturaleza de los contenedores.

Los contenedores son EFÍMEROS por diseño. Eso significa que no están pensados para guardar datos permanentes. Cuando un contenedor se borra, todo lo que había dentro desaparece con él. Es como una pizarra que se borra cada vez que alguien sale de la sala. Esto es una FEATURE, no un bug — los contenedores deben poder crearse y destruirse sin miedo. Pero entonces... ¿dónde guardamos los datos que SÍ queremos mantener?

### Volúmenes: la memoria permanente de Docker

La respuesta son los VOLÚMENES. Un volumen es como un disco duro externo que conectas al contenedor. El contenedor puede morir, borrarse, recrearse — pero el disco externo (el volumen) sigue ahí con tus datos intactos. Cuando creas un contenedor nuevo, simplemente vuelves a conectar el mismo disco externo y tus datos están donde los dejaste.

Los volúmenes sobreviven al ciclo de vida de los contenedores. Son la memoria permanente de Docker.

### Tipos de volúmenes

Docker tiene dos tipos principales de volúmenes. Ambos logran el mismo objetivo (persistir datos), pero de formas diferentes:

  • Named volumes (volúmenes con nombre): Docker los gestiona internamente. Tú solo les das un nombre y Docker decide dónde guardarlos en tu disco. Son ideales para bases de datos.
  • Bind mounts (montaje directo): Tú eliges exactamente qué carpeta de tu ordenador se conecta al contenedor. Son ideales para desarrollo — editas código en tu PC y el contenedor lo ve al instante.
1# docker-compose.yml con NAMED VOLUME para PostgreSQL
2services:
3 db:
4 image: postgres:16
5 environment:
6 POSTGRES_PASSWORD: secreto123
7 ports:
8 - "5432:5432"
9 volumes:
10 - pgdata:/var/lib/postgresql/data # Named volume
11
12volumes:
13 pgdata: # Declara el volumen con nombre

Named volume: Docker gestiona dónde se guardan los datos de PostgreSQL

Cuando hagas docker volume ls, no busques "pgdata" a secas. Docker Compose prefija los volúmenes con el nombre del directorio del proyecto: si tu carpeta se llama mi-proyecto, el volumen será mi-proyecto_pgdata. Es normal y esperado — no significa que algo haya fallado.

1# docker-compose.yml con BIND MOUNT para desarrollo
2services:
3 app:
4 build: .
5 volumes:
6 - ./src:/app/src # Tu carpeta local → dentro del contenedor
7 ports:
8 - "8000:8000"

Bind mount: tu código local se "sincroniza" con el contenedor en tiempo real

Consejo de senior: usa NAMED VOLUMES para datos de bases de datos (no quieres tocar esos archivos directamente). Usa BIND MOUNTS para tu código fuente durante desarrollo (quieres editar en tu IDE y que el cambio se refleje en el contenedor sin reconstruir la imagen).

Esto me costó DOS DÍAS la primera vez que usé Docker en Windows: si tu código está en /mnt/c/Users/... (el sistema de archivos de Windows montado en WSL2), los bind mounts son entre 10x y 50x más lentos. Tu contenedor tarda siglos en arrancar y hot-reload se convierte en cold-reload. La solución: guarda tus proyectos dentro del filesystem de Linux (\\wsl$\Ubuntu\home\tu-usuario\) o trabaja directamente desde la terminal de WSL. El día que lo cambié fue como quitarle el freno de mano al coche.

### Redes Docker: cómo se comunican los contenedores

docker-compose crea automáticamente una red interna para tus servicios — por eso en la lección anterior pudimos usar "db" como hostname. Pero a veces necesitas más control: separar servicios en redes diferentes, o conectar contenedores de diferentes docker-compose.yml. Para eso existen las redes explícitas.

1# docker-compose.yml con redes explícitas
2services:
3 db:
4 image: postgres:16
5 environment:
6 POSTGRES_PASSWORD: secreto123
7 networks:
8 - backend # Solo accesible desde la red "backend"
9
10 redis:
11 image: redis:7-alpine
12 networks:
13 - backend # Solo accesible desde la red "backend"
14
15 app:
16 build: .
17 networks:
18 - backend # Puede hablar con db y redis
19 - frontend # También expuesta al frontend
20 ports:
21 - "8000:8000"
22
23 web:
24 image: nginx:alpine
25 networks:
26 - frontend # Solo puede hablar con app, NO con db directamente
27 ports:
28 - "80:80"
29
30networks:
31 backend:
32 frontend:

Redes separadas: web no puede acceder directamente a la base de datos (seguridad por diseño)

Para data engineering, las redes explícitas son menos comunes (normalmente todos tus servicios necesitan hablar entre sí), pero es importante entender el concepto. La red por defecto que docker-compose crea es perfecta para el 90% de los casos.

CUIDADO con docker compose down -v — la flag -v borra los VOLÚMENES. Si tienes datos importantes en PostgreSQL y ejecutas esto, los pierdes para siempre. Usa docker compose down (sin -v) para parar servicios manteniendo los datos. Solo usa -v cuando QUIERAS empezar de cero.

### Gestionar volúmenes desde la terminal

1# Listar todos los volúmenes
2docker volume ls
3
4# Inspeccionar un volumen (ver dónde está en tu disco)
5docker volume inspect pgdata
6
7# Borrar un volumen específico
8docker volume rm pgdata
9
10# Borrar TODOS los volúmenes no usados (¡cuidado!)
11docker volume prune

Comandos para gestionar volúmenes manualmente

### Patrón profesional: desarrollo con hot-reload

En desarrollo, el patrón más común es usar un bind mount para tu código + un named volume para la base de datos. Así puedes editar tu código en VS Code y el contenedor lo ejecuta al instante, sin necesidad de reconstruir la imagen:

1# docker-compose.yml — patrón de desarrollo profesional
2services:
3 db:
4 image: postgres:16
5 environment:
6 POSTGRES_PASSWORD: secreto123
7 POSTGRES_DB: dev
8 ports:
9 - "5432:5432"
10 volumes:
11 - pgdata:/var/lib/postgresql/data # Datos persistentes
12
13 app:
14 build: .
15 volumes:
16 - ./src:/app/src # Código en hot-reload
17 - ./data:/app/data # Datasets locales
18 environment:
19 DATABASE_URL: postgresql://postgres:secreto123@db:5432/dev
20 depends_on:
21 - db
22 ports:
23 - "8000:8000"
24
25volumes:
26 pgdata:

El combo perfecto: named volume para DB + bind mount para código

Consejo de senior: mi regla de oro para volúmenes es simple. Pregúntate: "¿quién genera estos datos?" Si los genera una base de datos → named volume. Si los generas TÚ en tu IDE → bind mount. Si son datasets de prueba que van en Git → bind mount al directorio del repo.

## ejercicios

[01]

PostgreSQL con persistencia

Añade un volumen con nombre para que los datos de PostgreSQL sobrevivan a docker compose down.

Cargando editor...
[02]

Bind mount para desarrollo

Sincroniza tu código local con el contenedor: editas en VS Code y el contenedor lo ve al instante. El punto (./) es la clave.

Cargando editor...
[03]

Limpieza segura de Docker

Disco lleno. Limpia en orden, pero SIN borrar el volumen ventas_data. La clave: saber qué borra prune y qué no.

Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...