Volúmenes Docker: Persistencia de Datos - Guía Completa
Los volúmenes Docker son el mecanismo preferido para persistir datos generados y usados por contenedores Docker. A diferencia de los contenedores mismos, los volúmenes persisten más allá del ciclo de vida del contenedor, permitiendo compartir datos, respaldos y migraciones. Esta guía completa cubre todo sobre volúmenes Docker, desde conceptos básicos hasta estrategias avanzadas para producción.
Tabla de Contenidos
- Introducción a los Volúmenes Docker
- Requisitos Previos
- Tipos de Persistencia de Datos
- Volúmenes Nombrados
- Bind Mounts
- tmpfs Mounts
- Controladores de Volúmenes
- Comandos de Gestión de Volúmenes
- Uso de Volúmenes con Contenedores
- Volúmenes en Docker Compose
- Respaldo y Restauración
- Mejores Prácticas para Producción
- Resolución de Problemas
- Conclusión
Introducción a los Volúmenes Docker
Los contenedores son efímeros por diseño—cuando se eliminan, todos los datos dentro se pierden. Los volúmenes Docker resuelven esto proporcionando almacenamiento persistente que existe independientemente del ciclo de vida del contenedor. Los volúmenes son gestionados por Docker y almacenados fuera de la capa escribible del contenedor, ofreciendo mejor rendimiento y gestión más fácil.
¿Por Qué Usar Volúmenes Docker?
- Persistencia de Datos: Sobreviven reinicios y eliminaciones de contenedores
- Rendimiento: Mejor rendimiento de I/O que el sistema de archivos del contenedor
- Compartir: Compartir datos entre múltiples contenedores
- Respaldo: Más fácil de respaldar y restaurar
- Portabilidad: Mover datos entre hosts
- Seguridad: Pueden ser encriptados y controlados por acceso
Comparación de Tipos de Almacenamiento
| Característica | Volúmenes | Bind Mounts | tmpfs |
|---|---|---|---|
| Gestionado por Docker | Sí | No | No |
| Persistente | Sí | Sí | No |
| Compartible | Sí | Sí | No |
| Rendimiento | Alto | Medio | Más Alto |
| Portabilidad | Alta | Baja | N/A |
| Acceso desde host | Limitado | Directo | Ninguno |
Requisitos Previos
Antes de trabajar con volúmenes Docker, asegúrate de tener:
- Docker Engine instalado (versión 17.06 o superior)
- Comprensión básica de contenedores Docker
- Acceso sudo/root para algunas operaciones
- Comprensión de conceptos de sistema de archivos
Verificar instalación de Docker:
docker --version
docker info | grep "Storage Driver"
Tipos de Persistencia de Datos
1. Volúmenes Nombrados (Recomendado)
Gestionados por Docker, almacenados en el directorio de almacenamiento de Docker:
docker volume create my-volume
docker run -v my-volume:/app/data nginx
2. Bind Mounts
Mapeo directo al sistema de archivos del host:
docker run -v /host/path:/container/path nginx
3. tmpfs Mounts
Almacenamiento temporal en memoria (solo Linux):
docker run --tmpfs /app/temp nginx
Arquitectura de Volúmenes
Capa de Contenedor (efímera)
↓
Punto de Montaje de Volumen
↓
Volumen Docker (persistente)
↓
Sistema de Archivos del Host (/var/lib/docker/volumes/)
Volúmenes Nombrados
Los volúmenes nombrados son unidades de almacenamiento gestionadas por Docker con nombres explícitos, haciéndolos fáciles de referenciar y gestionar.
Crear Volúmenes Nombrados
# Crear volumen básico
docker volume create my-data
# Crear con opciones de controlador
docker volume create \
--driver local \
--opt type=none \
--opt device=/path/on/host \
--opt o=bind \
custom-volume
# Crear con etiquetas
docker volume create \
--label environment=production \
--label backup=daily \
prod-data
Ubicación de Almacenamiento de Volúmenes
# Ubicación predeterminada: /var/lib/docker/volumes/
sudo ls -la /var/lib/docker/volumes/
# Inspeccionar ubicación de volumen
docker volume inspect my-data
Usar Volúmenes Nombrados
# Ejecutar contenedor con volumen nombrado
docker run -d \
--name web \
-v my-data:/usr/share/nginx/html \
nginx
# Múltiples volúmenes
docker run -d \
--name app \
-v app-data:/app/data \
-v app-logs:/app/logs \
-v app-config:/app/config \
my-app:latest
Volumen con Opciones Específicas
# Volumen de solo lectura
docker run -d -v my-data:/app/data:ro nginx
# Volumen con opción nocopy (no copiar datos del contenedor)
docker run -d -v my-data:/app/data:nocopy nginx
# Etiqueta SELinux (para sistemas con SELinux habilitado)
docker run -d -v my-data:/app/data:z nginx # privado
docker run -d -v my-data:/app/data:Z nginx # compartido
Compartir Volúmenes Entre Contenedores
# Crear volumen
docker volume create shared-data
# Primer contenedor escribe datos
docker run -d \
--name writer \
-v shared-data:/data \
alpine sh -c 'echo "Hello" > /data/message.txt'
# Segundo contenedor lee datos
docker run --rm \
-v shared-data:/data \
alpine cat /data/message.txt
Ciclo de Vida del Volumen
# Crear volumen
docker volume create app-data
# Usar en contenedor
docker run -d --name app -v app-data:/data my-app
# Contenedor eliminado, volumen persiste
docker rm -f app
# Volumen aún existe
docker volume ls
# Eliminar volumen manualmente
docker volume rm app-data
Bind Mounts
Los bind mounts mapean un directorio o archivo del host directamente en un contenedor. Útil para desarrollo y cuando necesitas acceso directo al sistema de archivos del host.
Bind Mount Básico
# Montar directorio del host
docker run -d \
-v /host/path:/container/path \
nginx
# Usando sintaxis --mount (recomendado)
docker run -d \
--mount type=bind,source=/host/path,target=/container/path \
nginx
Flujo de Trabajo de Desarrollo
# Montar código fuente para desarrollo
docker run -d \
--name dev-container \
-v $(pwd)/app:/usr/src/app \
-v $(pwd)/app/node_modules:/usr/src/app/node_modules \
-p 3000:3000 \
node:18-alpine \
npm run dev
Bind Mount de Solo Lectura
# Montar como solo lectura
docker run -d \
-v /host/config:/app/config:ro \
nginx
# Usando --mount
docker run -d \
--mount type=bind,source=/host/config,target=/app/config,readonly \
nginx
Bind Mount de Archivo
# Montar archivo único
docker run -d \
-v /host/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx
Permisos de Bind Mount
# Preservar permisos
docker run -d \
-v /host/data:/container/data \
--user $(id -u):$(id -g) \
nginx
# Con usuario específico
docker run -d \
-v /host/data:/container/data \
--user 1000:1000 \
nginx
Ejemplo de Bind Mount: Desarrollo WordPress
# Montar fuente de WordPress y base de datos
docker run -d \
--name wordpress \
-v $(pwd)/wordpress:/var/www/html \
-v $(pwd)/uploads:/var/www/html/wp-content/uploads \
-p 8080:80 \
wordpress:latest
docker run -d \
--name mysql \
-v $(pwd)/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
tmpfs Mounts
Los tmpfs mounts son almacenamiento temporal solo en memoria. Los datos se pierden cuando el contenedor se detiene.
Crear tmpfs Mount
# tmpfs mount básico
docker run -d \
--tmpfs /app/temp \
nginx
# Usando sintaxis --mount
docker run -d \
--mount type=tmpfs,target=/app/temp \
nginx
# Con límite de tamaño
docker run -d \
--mount type=tmpfs,target=/app/temp,tmpfs-size=100m \
nginx
Casos de Uso de tmpfs
# Caché temporal
docker run -d \
--tmpfs /tmp:rw,noexec,nosuid,size=1g \
nginx
# Almacenamiento de sesiones
docker run -d \
--tmpfs /app/sessions:size=512m \
my-app
# Artefactos de construcción (no persistir)
docker run --rm \
--tmpfs /app/build:size=2g \
my-builder
Rendimiento de tmpfs
Perfecto para:
- Archivos temporales
- Caché que no necesita persistencia
- Datos sensibles (limpiados automáticamente)
- Requisitos de almacenamiento de alta velocidad
# Directorio temporal de base de datos
docker run -d \
--name postgres \
--tmpfs /var/lib/postgresql/tmp:size=1g \
-v postgres-data:/var/lib/postgresql/data \
postgres:15-alpine
Controladores de Volúmenes
Docker soporta varios controladores de volúmenes para diferentes backends de almacenamiento.
Controlador Local (Predeterminado)
# Controlador local predeterminado
docker volume create my-volume
# Local con opciones
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/share \
nfs-volume
Volumen NFS
# Crear volumen NFS
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=nfs-server.example.com,rw,nfsvers=4 \
--opt device=:/exported/path \
nfs-data
# Usar volumen NFS
docker run -d \
-v nfs-data:/app/data \
nginx
Plugins de Volúmenes de Terceros
# Instalar plugin (ejemplo: REX-Ray)
docker plugin install rexray/s3fs
# Crear volumen con plugin
docker volume create \
--driver rexray/s3fs \
--opt bucket=my-bucket \
s3-volume
Plugins de volúmenes populares:
- REX-Ray: AWS EBS, S3, etc.
- Portworx: Almacenamiento nativo de contenedores
- GlusterFS: Sistema de archivos distribuido
- Ceph: Almacenamiento distribuido
Comandos de Gestión de Volúmenes
Crear Volúmenes
# Crear volumen
docker volume create my-volume
# Crear con nombre
docker volume create --name production-data
# Con etiquetas
docker volume create \
--label app=myapp \
--label env=prod \
app-data
Listar Volúmenes
# Listar todos los volúmenes
docker volume ls
# Filtrar por nombre
docker volume ls -f name=app
# Filtrar por etiqueta
docker volume ls -f label=env=prod
# Mostrar volúmenes colgantes
docker volume ls -f dangling=true
Inspeccionar Volúmenes
# Inspeccionar volumen
docker volume inspect my-volume
# Obtener campo específico
docker volume inspect --format '{{.Mountpoint}}' my-volume
# Inspeccionar múltiples volúmenes
docker volume inspect volume1 volume2
Eliminar Volúmenes
# Eliminar volumen específico
docker volume rm my-volume
# Eliminar múltiples volúmenes
docker volume rm volume1 volume2 volume3
# Eliminar todos los volúmenes no usados
docker volume prune
# Forzar eliminación de todos los volúmenes (¡peligroso!)
docker volume rm $(docker volume ls -q)
Información de Volúmenes
# Obtener tamaño de volumen (requiere sudo)
sudo du -sh /var/lib/docker/volumes/my-volume
# Listar volúmenes con tamaño
docker system df -v
# Verificar uso de volumen
docker volume inspect my-volume | grep Mountpoint
Uso de Volúmenes con Contenedores
Múltiples Volúmenes
# Contenedor con múltiples volúmenes
docker run -d \
--name app \
-v app-data:/app/data \
-v app-logs:/var/log/app \
-v app-cache:/app/cache \
-v app-config:/etc/app:ro \
my-app:latest
Volumen desde Otro Contenedor
# Crear contenedor de datos
docker create -v /data --name data-container alpine
# Usar volúmenes del contenedor de datos
docker run -d \
--volumes-from data-container \
--name app \
nginx
Poblar Volumen desde Contenedor
# La imagen del contenedor tiene datos en /app/data
# La primera ejecución copia datos a volumen vacío
docker run -d \
--name app \
-v app-data:/app/data \
my-app:latest
# Ejecuciones subsiguientes usan datos de volumen existentes
docker rm -f app
docker run -d \
--name app \
-v app-data:/app/data \
my-app:latest
Volúmenes en Docker Compose
Configuración Básica de Volúmenes
version: '3.8'
services:
web:
image: nginx
volumes:
- html-data:/usr/share/nginx/html
database:
image: postgres:15-alpine
volumes:
- db-data:/var/lib/postgresql/data
volumes:
html-data:
db-data:
Volúmenes Nombrados con Opciones
version: '3.8'
services:
app:
image: my-app
volumes:
- app-data:/app/data
volumes:
app-data:
driver: local
driver_opts:
type: none
o: bind
device: /path/on/host
Bind Mounts en Compose
version: '3.8'
services:
web:
image: nginx
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf:ro
Volumen con NFS
version: '3.8'
services:
app:
image: my-app
volumes:
- nfs-data:/app/data
volumes:
nfs-data:
driver: local
driver_opts:
type: nfs
o: addr=nfs-server.example.com,rw
device: ":/exported/path"
Volúmenes Externos
version: '3.8'
services:
app:
image: my-app
volumes:
- existing-volume:/app/data
volumes:
existing-volume:
external: true
Ejemplo Completo de Compose
version: '3.8'
services:
wordpress:
image: wordpress:latest
volumes:
- wordpress-html:/var/www/html
- wordpress-uploads:/var/www/html/wp-content/uploads
environment:
WORDPRESS_DB_HOST: database
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
database:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql
- ./mysql-init:/docker-entrypoint-initdb.d:ro
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
backup:
image: alpine
volumes:
- wordpress-html:/backup/html:ro
- db-data:/backup/db:ro
- ./backups:/backups
command: sh -c "tar czf /backups/backup-$(date +%Y%m%d-%H%M%S).tar.gz /backup"
volumes:
wordpress-html:
wordpress-uploads:
db-data:
Respaldo y Restauración
Respaldar Volumen Nombrado
# Respaldar volumen a archivo tar
docker run --rm \
-v my-volume:/source:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/my-volume-backup.tar.gz -C /source .
# Respaldar con marca de tiempo
docker run --rm \
-v my-volume:/source:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /source .
Restaurar Volumen desde Respaldo
# Crear nuevo volumen
docker volume create my-volume-restored
# Restaurar desde respaldo
docker run --rm \
-v my-volume-restored:/target \
-v $(pwd):/backup \
alpine \
sh -c "cd /target && tar xzf /backup/my-volume-backup.tar.gz"
Respaldar Volumen de Base de Datos
# Respaldo PostgreSQL
docker run --rm \
-v postgres-data:/var/lib/postgresql/data:ro \
-v $(pwd):/backup \
postgres:15-alpine \
tar czf /backup/postgres-backup.tar.gz -C /var/lib/postgresql/data .
# Respaldo MySQL
docker exec mysql-container \
mysqldump -u root -p${DB_PASSWORD} --all-databases \
> mysql-backup.sql
Script de Respaldo Automatizado
#!/bin/bash
# backup-volumes.sh
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d-%H%M%S)
# Respaldar múltiples volúmenes
for volume in app-data db-data logs-data; do
docker run --rm \
-v ${volume}:/source:ro \
-v ${BACKUP_DIR}:/backup \
alpine \
tar czf /backup/${volume}-${DATE}.tar.gz -C /source .
done
# Limpiar respaldos antiguos (mantener últimos 7 días)
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +7 -delete
Migrar Volumen a Otro Host
# En host fuente: Exportar volumen
docker run --rm \
-v my-volume:/source:ro \
alpine \
tar c -C /source . | ssh user@destination-host 'cat > /tmp/volume-export.tar'
# En host destino: Importar volumen
docker volume create my-volume
cat /tmp/volume-export.tar | docker run --rm -i \
-v my-volume:/target \
alpine \
tar x -C /target
Mejores Prácticas para Producción
Usar Volúmenes Nombrados
# Bueno: Volumen nombrado
docker run -d -v postgres-data:/var/lib/postgresql/data postgres
# Evitar: Volumen anónimo
docker run -d -v /var/lib/postgresql/data postgres
Convención de Nombres de Volúmenes
# Incluir entorno y propósito
docker volume create prod-app-data
docker volume create prod-db-data
docker volume create staging-cache
Etiquetar Volúmenes
docker volume create \
--label environment=production \
--label backup=daily \
--label app=myapp \
--label retention=30d \
prod-app-data
Montajes de Solo Lectura
# La configuración debe ser de solo lectura
docker run -d \
-v config-data:/etc/app:ro \
-v app-data:/app/data \
my-app
Monitoreo de Volúmenes
# Verificar tamaños de volúmenes
docker system df -v
# Monitorear volumen específico
watch -n 5 'sudo du -sh /var/lib/docker/volumes/my-volume/_data'
Estrategia de Respaldo
# Agregar servicio de respaldo a compose
services:
backup:
image: alpine
volumes:
- app-data:/data:ro
- ./backups:/backups
command: >
sh -c "while true; do
tar czf /backups/backup-$$(date +%Y%m%d-%H%M%S).tar.gz /data;
sleep 86400;
done"
Consideraciones de Seguridad
# Ejecutar con usuario específico
docker run -d \
--user 1000:1000 \
-v app-data:/app/data \
my-app
# Usar secretos para datos sensibles (Swarm)
echo "password" | docker secret create db_password -
docker service create \
--secret db_password \
--mount source=db-data,target=/var/lib/mysql \
mysql
Límites de Recursos
# Limitar tamaño de volumen (requiere controlador de almacenamiento específico)
docker volume create \
--driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=100m,uid=1000 \
limited-volume
Resolución de Problemas
Volumen No Se Monta
# Verificar si el volumen existe
docker volume ls | grep my-volume
# Inspeccionar volumen
docker volume inspect my-volume
# Verificar montaje del contenedor
docker inspect container-name | grep -A 10 Mounts
# Verificar permisos
sudo ls -la /var/lib/docker/volumes/my-volume/_data
Errores de Permiso Denegado
# Verificar propiedad
docker exec container-name ls -la /app/data
# Corregir permisos desde contenedor
docker exec container-name chown -R appuser:appuser /app/data
# O usar usuario apropiado
docker run -d --user $(id -u):$(id -g) -v my-volume:/data my-app
Datos del Volumen No Persisten
# Verificar que el volumen se usa realmente
docker inspect container-name | grep -A 20 Mounts
# Verificar si se usa volumen anónimo
docker volume ls -f dangling=true
# Asegurar que el contenedor escribe en ruta montada
docker exec container-name touch /data/test.txt
docker run --rm -v my-volume:/data alpine ls -la /data
Volumen Lleno
# Verificar tamaño de volumen
docker system df -v
# Encontrar archivos grandes
docker run --rm -v my-volume:/data alpine du -sh /data/*
# Limpiar datos antiguos
docker exec container-name find /data -mtime +30 -delete
No Se Puede Eliminar Volumen
# Encontrar contenedores usando volumen
docker ps -a --filter volume=my-volume
# Detener y eliminar contenedores
docker rm -f $(docker ps -a -q --filter volume=my-volume)
# Eliminar volumen
docker volume rm my-volume
Problemas de Rendimiento
# Verificar controlador de almacenamiento
docker info | grep "Storage Driver"
# Usar tmpfs para almacenamiento temporal de alto rendimiento
docker run -d --tmpfs /app/temp:size=1g my-app
# Considerar opciones de controlador de volumen
docker volume create \
--driver local \
--opt type=none \
--opt o=bind \
--opt device=/fast/storage/path \
fast-volume
Conclusión
Los volúmenes Docker proporcionan persistencia de datos robusta y flexible para aplicaciones contenerizadas. Comprender volúmenes, bind mounts y tmpfs mounts es esencial para despliegues de producción.
Puntos Clave
- Volúmenes Nombrados: Método preferido, gestionado por Docker, portable
- Bind Mounts: Flujos de trabajo de desarrollo, acceso directo al host
- tmpfs: Almacenamiento temporal, alto rendimiento, solo en memoria
- Persistencia: Los datos sobreviven al ciclo de vida del contenedor
- Compartir: Múltiples contenedores pueden usar el mismo volumen
- Respaldo: Los respaldos regulares son esenciales para producción
Referencia Rápida
# Gestión de Volúmenes
docker volume create my-volume # Crear volumen
docker volume ls # Listar volúmenes
docker volume inspect my-volume # Inspeccionar volumen
docker volume rm my-volume # Eliminar volumen
docker volume prune # Eliminar no usados
# Usar Volúmenes
docker run -v my-volume:/data nginx # Volumen nombrado
docker run -v /host:/container nginx # Bind mount
docker run --tmpfs /tmp nginx # tmpfs mount
docker run -v my-volume:/data:ro nginx # Solo lectura
# Respaldo y Restauración
# Respaldar
docker run --rm -v my-volume:/source:ro -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz -C /source .
# Restaurar
docker run --rm -v my-volume:/target -v $(pwd):/backup alpine tar xzf /backup/backup.tar.gz -C /target
Próximos Pasos
- Implementar: Usar volúmenes en tus aplicaciones
- Respaldar: Configurar estrategia de respaldo automatizada
- Monitorear: Rastrear tamaños y uso de volúmenes
- Asegurar: Implementar permisos y encriptación adecuados
- Optimizar: Elegir controladores de almacenamiento apropiados
- Escalar: Explorar soluciones de almacenamiento distribuido
- Documentar: Mantener inventario y procedimientos de volúmenes
La gestión adecuada de volúmenes asegura persistencia de datos, portabilidad y confiabilidad en tu infraestructura contenerizada.


