13-Persistencia de Datos en MySQL con Docker Volumes
Persistencia de Datos en MySQL con Docker Volumes
Introducción
En este tutorial configuraremos un volumen persistente para la base de datos MySQL, asegurando que los datos no se pierdan al detener o eliminar los contenedores.
Paso 1: Importancia de los Volúmenes Persistentes
¿Por qué necesitamos un volumen?
| Sin Volumen | Con Volumen |
|---|---|
| Los datos se pierden al detener el contenedor | Los datos persisten entre reinicios |
Cada docker compose down elimina la base de datos | La base de datos mantiene su estado |
| No apto para desarrollo ni producción | Ideal para desarrollo y producción |
Paso 2: Verificar Configuración Actual
2.1 Ver estado de los contenedores
# Verificar contenedores activos docker compose ps # Ver volúmenes existentes docker volume ls
2.2 Estructura actual de docker-compose.yml
# Ver contenido actual cat docker-compose.yml
Paso 3: Agregar Volumen al Servicio de Base de Datos
3.1 Abrir el archivo de configuración
nano docker-compose.yml3.2 Modificar el servicio db
Agregar la sección volumes al servicio db:
services: db: image: mysql:8.0 container_name: laravel_db restart: unless-stopped environment: MYSQL_DATABASE: ${DB_DATABASE:-laravel} MYSQL_USER: ${DB_USERNAME:-laravel} MYSQL_PASSWORD: ${DB_PASSWORD:-secret} MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret} ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql networks: - laravel
Explicación:
mysql_data: Nombre del volumen (debe coincidir con la definición)/var/lib/mysql: Ruta donde MySQL almacena los datos dentro del contenedor
Paso 4: Definir el Volumen en la Sección Global
4.1 Agregar la sección volumes al final del archivo
volumes: mysql_data:
Archivo completo con la sección:
version: '3.8' services: app: build: context: . dockerfile: Dockerfile args: USERNAME: ${USER:-laravel} USERID: ${UID:-1000} image: laravel-app container_name: laravel_app restart: unless-stopped working_dir: /var/www/html volumes: - ./:/var/www/html networks: - laravel depends_on: - db - redis nginx: image: nginx:alpine container_name: laravel_nginx restart: unless-stopped ports: - "8000:80" volumes: - ./:/var/www/html - ./docker/nginx:/etc/nginx/conf.d networks: - laravel depends_on: - app db: image: mysql:8.0 container_name: laravel_db restart: unless-stopped environment: MYSQL_DATABASE: ${DB_DATABASE:-laravel} MYSQL_USER: ${DB_USERNAME:-laravel} MYSQL_PASSWORD: ${DB_PASSWORD:-secret} MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret} ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql networks: - laravel networks: laravel: driver: bridge volumes: mysql_data:
Paso 5: Verificar la Configuración
5.1 Verificar sintaxis
# Validar el archivo docker-compose.yml docker compose config # Si hay errores, revisar indentación (2 espacios, no tabs)
5.2 Errores comunes al definir volúmenes
# ❌ INCORRECTO (indentación incorrecta) volumes: - mysql_data:/var/lib/mysql # ❌ INCORRECTO (nombre no coincide) volumes: - mysql-database:/var/lib/mysql # Nombre diferente # ✅ CORRECTO volumes: - mysql_data:/var/lib/mysql
Paso 6: Comandos para Gestionar Volúmenes
6.1 Levantar contenedores con volumen
# Levantar los servicios (se crea el volumen automáticamente) docker compose up -d # Verificar que el volumen se haya creado docker volume ls
Salida esperada:
DRIVER VOLUME NAME local laravel_mysql_data
6.2 Ver información del volumen
# Inspeccionar el volumen docker volume inspect laravel_mysql_data
Salida:
[ { "CreatedAt": "2024-xx-xxTxx:xx:xxZ", "Driver": "local", "Labels": { "com.docker.compose.project": "laravel", "com.docker.compose.version": "2.xx.x" }, "Mountpoint": "/var/lib/docker/volumes/laravel_mysql_data/_data", "Name": "laravel_mysql_data", "Options": null, "Scope": "local" } ]
6.3 Ubicación física del volumen en el host
# Ver dónde se almacenan los datos ls -la /var/lib/docker/volumes/laravel_mysql_data/_data/
Paso 7: Prueba de Persistencia
7.1 Crear datos en la base de datos
# Entrar al contenedor de MySQL docker compose exec db mysql -u root -prootsecret # Dentro de MySQL CREATE DATABASE test_persist; USE test_persist; CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100)); INSERT INTO users (name) VALUES ('Test User'); SELECT * FROM users; EXIT;
7.2 Detener y eliminar contenedores
# Detener contenedores SIN eliminar el volumen docker compose down # Verificar que el volumen aún existe docker volume ls
7.3 Volver a levantar contenedores
docker compose up -d # Verificar que los datos persisten docker compose exec db mysql -u root -prootsecret -e "SELECT * FROM test_persist.users;"
Paso 8: Actualizaciones y Buenas Prácticas (2024-2026)
✅ Volúmenes con drivers personalizados
volumes: mysql_data: driver: local driver_opts: type: none device: /home/user/docker/mysql # Ruta alternativa o: bind
✅ Volúmenes nombrados vs bind mounts
| Tipo | Sintaxis | Caso de uso |
|---|---|---|
| Volumen nombrado | mysql_data:/var/lib/mysql | Persistencia general |
| Bind mount | ./mysql-data:/var/lib/mysql | Desarrollo, acceso directo |
✅ Backup automático con volume
# Crear backup del volumen docker run --rm -v laravel_mysql_data:/data -v $(pwd):/backup alpine \ tar czf /backup/mysql_backup_$(date +%Y%m%d).tar.gz -C /data .
✅ Restaurar backup
docker run --rm -v laravel_mysql_data:/data -v $(pwd):/backup alpine \ tar xzf /backup/mysql_backup_20240101.tar.gz -C /data
✅ Volumen para múltiples servicios
volumes: mysql_data: redis_data: app_storage:
Paso 9: Comandos Avanzados de Volúmenes
9.1 Ver espacio usado por volúmenes
docker system df -v
9.2 Eliminar volumen huérfano
# Eliminar volumen específico docker volume rm laravel_mysql_data # Eliminar volúmenes no usados docker volume prune
9.3 Copiar datos entre volúmenes
# Copiar datos de un volumen a otro docker run --rm -v source_volume:/source -v target_volume:/target alpine \ cp -av /source/. /target/
Errores Comunes y Soluciones
| Error | Causa | Solución |
|---|---|---|
volume name conflicts | Nombre en uso | Usar nombre único o docker volume rm |
permission denied | Permisos de escritura | sudo chown -R 1001:1001 /var/lib/docker/volumes/... |
no such volume | No definido en volumes: | Agregar la sección global |
data lost | Volumen no montado | Verificar indentación en YAML |
port conflict | Puerto ocupado | Cambiar puerto en ports: |
Resumen: Configuración de Volúmenes
# Estructura de volúmenes en docker-compose.yml services: db: volumes: - nombre_volumen:/ruta/en/contenedor # Montar volumen volumes: nombre_volumen: # Declarar volumen # Opciones opcionales
Comentarios
Publicar un comentario