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.
### 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 PostgreSQL2services:3 db:4 image: postgres:165 environment:6 POSTGRES_PASSWORD: secreto1237 ports:8 - "5432:5432"9 volumes:10 - pgdata:/var/lib/postgresql/data # Named volume1112volumes: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 desarrollo2services:3 app:4 build: .5 volumes:6 - ./src:/app/src # Tu carpeta local → dentro del contenedor7 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ícitas2services:3 db:4 image: postgres:165 environment:6 POSTGRES_PASSWORD: secreto1237 networks:8 - backend # Solo accesible desde la red "backend"910 redis:11 image: redis:7-alpine12 networks:13 - backend # Solo accesible desde la red "backend"1415 app:16 build: .17 networks:18 - backend # Puede hablar con db y redis19 - frontend # También expuesta al frontend20 ports:21 - "8000:8000"2223 web:24 image: nginx:alpine25 networks:26 - frontend # Solo puede hablar con app, NO con db directamente27 ports:28 - "80:80"2930networks: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úmenes2docker volume ls34# Inspeccionar un volumen (ver dónde está en tu disco)5docker volume inspect pgdata67# Borrar un volumen específico8docker volume rm pgdata910# 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 profesional2services:3 db:4 image: postgres:165 environment:6 POSTGRES_PASSWORD: secreto1237 POSTGRES_DB: dev8 ports:9 - "5432:5432"10 volumes:11 - pgdata:/var/lib/postgresql/data # Datos persistentes1213 app:14 build: .15 volumes:16 - ./src:/app/src # Código en hot-reload17 - ./data:/app/data # Datasets locales18 environment:19 DATABASE_URL: postgresql://postgres:secreto123@db:5432/dev20 depends_on:21 - db22 ports:23 - "8000:8000"2425volumes: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
PostgreSQL con persistencia
Añade un volumen con nombre para que los datos de PostgreSQL sobrevivan a docker compose down.
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.
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.
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...