Persistencia de Datos en Docker
Por defecto, los datos de un contenedor se almacenan en su capa de escritura. Cuando el contenedor es eliminado, todos estos datos se pierden permanentemente. Para solucionar esto, Docker proporciona mecanismos de persistencia de datos.
Existen dos métodos principales para lograr la persistencia:
- Montajes de enlace (Bind Mounts): mapean directorios del host al contenedor
- Volúmenes (Volumes): gestionados completamente por Docker
Montajes de Enlace (Bind Mounts)
| Ubicación | Cualquier ruta del sistema operativo host |
|---|---|
| Acceso | Procesos del host pueden acceder directamente |
| Uso típico | Entornos de desarrollo - sincronización de código |
Ejemplo de montaje de enlace:
docker run -v /ruta/host:/ruta/contenedor nombre_imagen
Ejemplo práctico con MySQL:
[root@servidor ~]# docker run -itd -p 3306:3306 --name mysql-server -e MYSQL_ROOT_PASSWORD="password123" -v /datos/mysql:/var/lib/mysql mysql:8.0.42
abc123def456789...
[root@servidor ~]# ls -la /datos/mysql/
total 4096
drwxr-xr-x 1 root root 4096 ago 15 10:30 .
Volúmenes de Docker
| Ubicación | /var/lib/docker/volumes/ |
|---|---|
| Gestión | Exclusivamente por Docker |
| Uso recomendado | Entornos de producción |
Comando básico:
docker run -v nombre_volumen:/ruta/contenedor nombre_imagen
Tipos de Volúmenes
Volúmenes Nombrados: tienen un nombre específico definido por el usuario
Volúmenes Anónimos: Docker genera automáticamente un identificador hash como nombre
Creación explícita de volumen nombrado
# Paso 1: Crear el volumen manualmente
[root@servidor ~]# docker volume create db_mysql
db_mysql
# Paso 2: Verificar que fue creado
[root@servidor ~]# docker volume ls
DRIVER VOLUME NAME
local db_mysql
# Paso 3: Ejecutar contenedor usando el volumen
[root@servidor ~]# docker run -itd -p 3307:3306 --name mysql-product -e MYSQL_ROOT_PASSWORD="password123" -v db_mysql:/var/lib/mysql mysql:8.0.42
def789abc012...
Creación implícita de volumen nombrado
Si se especifica un volumen que no existe, Docker lo crea automáticamente:
[root@servidor ~]# docker run -itd -p 3308:3306 --name mysql-app -e MYSQL_ROOT_PASSWORD="password123" -v datos_app:/var/lib/mysql mysql:8.0.42
ghi456def789...
# Docker crea automáticamente el volumen
[root@servidor ~]# docker volume ls
DRIVER VOLUME NAME
local db_mysql
local datos_app
Creación implícita de volumen anónimo
# Al omitir el nombre, Docker genera un volumen anónimo
docker run -v /ruta/interna ...
Declaración de volumen en Dockerfile
La instrucción VOLUME en Dockerfile crea automáticamente un volumen anónimo al iniciar el contenedor:
# En Dockerfile:
# VOLUME /var/lib/postgresql/data
[root@servidor docker]# docker run -itd -p 3309:3306 --name mysql-test -e MYSQL_ROOT_PASSWORD="password123" mysql:8.0.42
jkl012mno345...
[root@servidor docker]# docker volume ls
DRIVER VOLUME NAME
local 123abc456def789... (volumen anónimo generado)
local db_mysql
local datos_app
Estructura de Almacenamiento de Docker
El directorio predeterminado de datos es: /var/lib/docker/
/var/lib/docker/
├── containers/ # Metadatos de contenedores (configuración, logs)
├── overlay2/ # Capas del sistema de archivos del contenedor
├── volumes/ # Almacenamiento de volúmenes
└── image/ # Metadatos de imágenes
Composición del Almacenamiento de Contenedores
- Capas del sistema de archivos (overlay2)
- Almacena la capa de escritura del contenedor
- Utiliza el sistema de archivos联合 (OverlayFS) para almacenamiento estratificado
- Metadatos del contenedor (containers)
- Cada contenedor tiene un subdirectorio (nombrado con su ID)
- Contiene: config.v2.json, hostname, hosts, logs JSON
- Almacenamiento de volúmenes (volumes)
- Volúmenes nombrados: /var/lib/docker/volumes/<nombre>/_data
- Volúmenes anónimos: /var/lib/docker/volumes/<id_random>/_data
Inspección de Docker y Volúmenes
Ver información detallada de un contenedor
[root@servidor docker]# docker inspect ghi456def789
[
{
"Id": "ghi456def789abc123...",
"Created": "2025-07-01T17:25:00.123456789Z",
"Path": "docker-entrypoint.sh",
"Args": ["mysqld"],
"State": {
"Status": "running",
"Running": true,
...
},
"Mounts": [
{
"Type": "volume",
"Name": "datos_app",
"Source": "/var/lib/docker/volumes/datos_app/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"RW": true
}
],
...
}
]
Filtrar información específica
# Ver directorio MergedDir
[root@servidor docker]# docker inspect ghi456def789 --format '{{.GraphDriver.Data.MergedDir}}'
/var/lib/docker/overlay2/abc123def456.../merged
# Ver mounts
[root@servidor docker]# docker inspect ghi456def789 | grep Mounts -A 15
"Mounts": [
{
"Type": "volume",
"Name": "datos_app",
"Source": "/var/lib/docker/volumes/datos_app/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "z",
"RW": true
}
],
Comandos para volúmenes
# Listar todos los volúmenes
docker volume ls
# Inspecionar un volumen específico
docker volume inspect db_mysql
# Limpiar volúmenes sin uso
docker volume prune
Ejemplo de inspección:
[root@servidor ~]# docker volume inspect db_mysql
[
{
"CreatedAt": "2025-07-02T01:20:00+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/db_mysql/_data",
"Name": "db_mysql",
"Options": null,
"Scope": "local"
}
]
Uso de almacenamiento de Docker
# Mostrar uso de disco de imágenes, contenedores y volúmenes
docker system df -v
Extracción de Archivos desde Imágenes
A veces es necesario copiar archivos de una imagen sin ejecutar el contenedor:
[root@servidor config]# docker create --name contenedor-temporal mysql:8.0.42
mno789pqr012...
[root@servidor config]# docker cp contenedor-temporal:/etc/mysql/my.cnf /data/config/my.cnf
Successfully copied 2.5kB to /data/config/my.cnf
[root@servidor config]# docker rm contenedor-temporal
contenedor-temporal
Montaje de Archivos de Configuración
Para sobrescribir archivos de configuración del contenedor:
[root@servidor config]# docker run -itd -p 3310:3306 --name mysql-custom -e MYSQL_ROOT_PASSWORD="password123" -v /data/config/my.cnf:/etc/my.cnf mysql:8.0.42
stu345vwx678...
# Verificar configuración desde el host
[root@servidor config]# docker exec mysql-custom cat /etc/my.cnf
[mysqld]
bind-address = 0.0.0.0
max_connections = 300
innodb_file_per_table = 1
Reglas de Sobreescritura de Datos
| Escenario | Comportamiento al iniciar | Ejemplo |
|---|---|---|
| Nuevo volumen nombrado | Contenido del contenedor → volumen | Inicializar base de datos |
| Volumen nombrado existente | Contenido del volumen → contenedor | Restaurar respaldo |
| Directorio host vacío | Contenido del contenedor → host | Sincronizar código en desarrollo |
| Directorio host no vacío | Contenido del host → contenedor | Configuración de producción |
| VOLUME en Dockerfile | Crea volumen anónimo y sobrescribe | Proteger datos importantes |
Gestión del Ciclo de Vida de los Datos
| Tipo de dato | Ubicación | Persiste tras eliminar contenedor |
|---|---|---|
| Capa de escritura del contenedor | overlay2 | NO - se elimina inmediatamente |
| Volumen nombrado | volumes | SÍ |
| Montaje de enlace | Ruta especificada por usuario | SÍ |
| Volumen anónimo | volumes | SÍ - requiere limpieza manual |
Selección del Método de Almacenamiento
Recomendaciones según el caso de uso:
| Escenario | Solución recomendada | Notas importantes |
|---|---|---|
| Archivos de configuración | Montaje de enlace | Usar modo solo lectura (ro) |
| Caché temporal | Volumen anónimo | Combinar con --rm para limpieza automática |
| Datos compartidos entre contenedores | Volumen nombrado | Considerar problemas de escritura concurrente |
| Almacenamiento de base de datos | Volumen nombrado + respaldos periódicos | Verificar que el driver sea adecuado para el tipo de E/S |
Importante: Evitar almacenar datos importantes únicamente en la capa de escritura del contenedor.