Los volúmenes de Docker son carpetas especiales que guardan datos fuera del contenedor, así esos datos sobreviven aunque el contenedor se detenga o elimine.
El problema que los volúmenes resuelven
Imagina que trabajas en el equipo de tecnología de Liverpool. Tienes un contenedor con una base de datos que registra pedidos en línea. El contenedor funciona bien toda la semana. Llega el viernes y alguien ejecuta docker rm para limpiar el servidor. El lunes por la mañana descubren que todos los pedidos del jueves desaparecieron. Ese es exactamente el problema que los volúmenes resuelven.
Por defecto, los datos que crea un contenedor viven dentro de su capa de escritura. Cuando el contenedor muere, esa capa muere con él. Los volúmenes rompen esa dependencia: guardan los datos en el sistema operativo del servidor, no dentro del contenedor.
El sistema CAJA-ESTANTE
Para entender los volúmenes, usa esta analogía: el contenedor es una caja de cartón y el volumen es un estante fijo en la pared. Puedes tirar la caja y comprar una nueva. El estante sigue ahí con todo lo que pusiste encima.
Este sistema tiene tres piezas:
- El volumen — el estante, gestionado por Docker.
- El punto de montaje — la ruta dentro del contenedor donde el estante queda visible.
- El contenedor — la caja que usa el estante mientras vive.
Cuando montas un volumen en un contenedor, todo lo que ese contenedor escriba en esa ruta se guarda automáticamente en el estante. Si creas un contenedor nuevo y montas el mismo volumen, los datos siguen ahí.
Tres tipos de almacenamiento en Docker
Antes de crear tu primer volumen, conviene conocer las tres opciones que Docker ofrece:
| Tipo | ¿Quién lo gestiona? | Caso de uso típico |
|---|---|---|
| Volumen | Docker | Bases de datos, archivos de app |
| Bind mount | Tú (ruta del host) | Desarrollo local, código fuente |
| tmpfs | Memoria RAM | Datos temporales sensibles |
En esta lección nos enfocamos en volúmenes y bind mounts, que son los que usarás el 95% del tiempo en proyectos reales.
Cómo crear y usar un volumen
Crear un volumen es una sola línea:
docker volume create datos_pedidos
Docker registra ese volumen en su propio directorio interno. Puedes listar todos tus volúmenes así:
docker volume ls
Ahora monta ese volumen cuando inicias un contenedor. Usa la bandera -v seguida del nombre del volumen, dos puntos y la ruta dentro del contenedor:
docker run -d \
-v datos_pedidos:/app/data \
--name tienda_liverpool \
mi_app_tienda:1.0
En este ejemplo, todo lo que la aplicación escriba en /app/data queda guardado en el volumen datos_pedidos. Si eliminas el contenedor tienda_liverpool y creas uno nuevo con el mismo comando, los archivos siguen ahí.
Ejemplo real: base de datos para un sistema de nómina
Supón que desarrollas un sistema de nómina para una empresa con 200 empleados. Usas PostgreSQL como base de datos. Sin volumen, si el contenedor de Postgres se reinicia, pierdes todo el historial de pagos.
Así se lanza PostgreSQL con un volumen:
docker volume create nomina_db
docker run -d \
--name postgres_nomina \
-e POSTGRES_PASSWORD=clave_segura \
-e POSTGRES_DB=nomina \
-v nomina_db:/var/lib/postgresql/data \
postgres:15-alpine
La ruta /var/lib/postgresql/data es donde Postgres guarda sus archivos internos. Al montarla en nomina_db, cada registro de empleado, cada cálculo de IMSS y cada comprobante queda persistido en el servidor, no dentro del contenedor.
Si necesitas actualizar Postgres a una versión nueva, simplemente detienes el contenedor viejo, creas uno nuevo con la versión actualizada y montas el mismo volumen. Los datos migran sin problema.
Bind mounts: el volumen del desarrollador
Durante el desarrollo local, necesitas algo diferente: que los cambios en tu código se reflejen en el contenedor sin reconstruir la imagen. Para eso usas un bind mount.
Un bind mount conecta una carpeta de tu computadora directamente con una ruta del contenedor:
docker run -d \
-v $(pwd)/src:/app/src \
--name dev_femsa \
mi_app:dev
Aquí $(pwd)/src es la carpeta src de tu proyecto en tu Mac o Linux. /app/src es donde el contenedor la ve. Cada vez que editas un archivo en src/, el contenedor lo detecta al instante.
Esto es especialmente útil cuando trabajas con herramientas como Nodemon o Flask en modo debug. El servidor se recarga solo al detectar cambios, sin necesidad de hacer docker build cada vez.
Regla importante: usa bind mounts en desarrollo. Usa volúmenes en producción. Los bind mounts dependen de la estructura de carpetas de tu máquina, lo que los hace frágiles en servidores.
Cómo inspeccionar un volumen
Puedes ver los detalles de cualquier volumen con:
docker volume inspect datos_pedidos
Eso te muestra algo así:
[
{
"Name": "datos_pedidos",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/datos_pedidos/_data",
"CreatedAt": "2024-03-15T10:30:00Z"
}
]
El campo Mountpoint te dice exactamente dónde Docker guarda esos datos en tu servidor. En producción, ese directorio debería estar en un disco con respaldos automáticos.
Errores comunes al usar volúmenes
Error 1: Olvidar montar el volumen en el contenedor nuevo
Cuando alguien elimina un contenedor y crea uno nuevo, a veces olvida agregar la bandera -v. El contenedor arranca sin el volumen y la aplicación empieza con datos vacíos. Siempre verifica que el nuevo contenedor tenga el mismo montaje.
Error 2: Confundir volúmenes anónimos con volúmenes nombrados
Si ejecutas docker run -v /app/data mi_imagen sin dar nombre al volumen, Docker crea un volumen anónimo con un ID largo como a3f9c2.... Esos volúmenes son difíciles de rastrear y se acumulan con el tiempo. Siempre dale un nombre descriptivo a tus volúmenes.
Error 3: No limpiar volúmenes huérfanos
Cuando eliminas contenedores, los volúmenes no se eliminan automáticamente. Con el tiempo acumulan gigabytes de datos obsoletos. Limpia volúmenes sin uso con:
docker volume prune
Ese comando elimina solo los volúmenes que no están montados en ningún contenedor activo. Es seguro ejecutarlo para limpiar el servidor.
Error 4: Guardar secretos en volúmenes sin cifrar
Un volumen es una carpeta en disco. Si alguien tiene acceso al servidor, puede leer esos archivos. Nunca guardes contraseñas o tokens de API directamente en un volumen sin cifrado adicional. Para secretos, usa variables de entorno o herramientas como Docker Secrets.
Ejemplo con Docker Compose
En proyectos reales casi siempre usarás Docker Compose para orquestar varios servicios. Aquí un ejemplo para una app de inventario similar a la que podría usar Bimbo en sus plantas:
version: "3.9"
services:
app:
image: inventario_bimbo:2.1
volumes:
- ./src:/app/src
depends_on:
- db
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: inventario
POSTGRES_PASSWORD: clave_produccion
volumes:
- inventario_db:/var/lib/postgresql/data
volumes:
inventario_db:
Fíjate en la sección volumes: al final del archivo. Ahí declaras los volúmenes nombrados que usa tu proyecto. Compose los crea automáticamente si no existen. El servicio app usa un bind mount para desarrollo. El servicio db usa un volumen nombrado para persistencia.
Verificar que los datos persisten
Prueba esto en tu máquina para confirmar que los volúmenes funcionan:
# Paso 1: crea un volumen y un contenedor
docker volume create prueba_volumen
docker run -d --name contenedor_a \
-v prueba_volumen:/datos \
alpine sh -c "echo 'Hola desde Liverpool' > /datos/archivo.txt && sleep 3600"
# Paso 2: elimina el contenedor
docker rm -f contenedor_a
# Paso 3: crea un contenedor nuevo con el mismo volumen
docker run --rm \
-v prueba_volumen:/datos \
alpine cat /datos/archivo.txt
El resultado en pantalla será:
Hola desde Liverpool
El contenedor contenedor_a ya no existe, pero su archivo sigue vivo en el volumen. Eso es exactamente la persistencia que necesitas en producción.
Los volúmenes son el puente entre la naturaleza efímera de los contenedores y la permanencia que exigen los datos reales de negocio.