Guía completa de despliegue de MySQL con Docker: persistencia de datos y replicación maestro-esclavo

Ese mensaje de error en la terminal te clava en el pecho: quince días de datos de prueba, desaparecidos. Por la tarde reinicié el contenedor de MySQL, pensando que era un reinicio normal, y los datos se fueron con el contenedor.
Desplegar MySQL con Docker parece sencillo: docker run -e MYSQL_ROOT_PASSWORD=123456 mysql y listo. Pero cuando reinicias el contenedor y los datos desaparecen, el montaje de configuración no surte efecto, la app local no conecta o en producción hay que montar replicación maestro-esclavo — esos agujeros solo los conoces cuando los pisas. En este artículo vamos de la persistencia de datos a la replicación maestro-esclavo, con cada configuración explicada al detalle.
Fundamentos del despliegue de MySQL en instancia única con Docker
La forma más simple de arrancar (y por qué no la recomendamos)
Empecemos por el error más habitual. Mucha gente, la primera vez que instala MySQL con Docker, hace algo así:
docker run --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0
Arranca, el contenedor está bien, entras y operas la base de datos: todo perfecto. Pero es una bomba de relojería.
¿Por qué? Los contenedores son efímeros por naturaleza. Si borras el contenedor o un día reinicias sin más, los datos se pierden. MySQL guarda los datos por defecto en /var/lib/mysql dentro del contenedor; al eliminar el contenedor, ese directorio desaparece.
La primera vez que caí en esta trampa pensé que MySQL tenía un bug. Luego entendí que no era MySQL: simplemente no había configurado persistencia de datos.
Persistencia de datos: montar volumes correctamente
En resumen, persistir datos es mapear el directorio de datos de MySQL al host para que, si el contenedor cae, los datos sigan ahí.
Docker ofrece tres formas de montaje:
- bind mount: mapeas un directorio del host, por ejemplo
/home/mysql/data - named volume: volumen gestionado por Docker, sin preocuparte de la ruta física
- tmpfs: almacenamiento en memoria; al reiniciar se pierde, casi no se usa
En 2024 Docker recomienda named volume; el rendimiento ya es muy parecido al bind mount. Yo uso ambos según el escenario: en desarrollo, named volume por comodidad; en producción, bind mount para facilitar backups.
Comando completo:
docker run --name mysql-persistent \
-e MYSQL_ROOT_PASSWORD=rootpwd123 \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
-d mysql:8.0
Aquí -v mysql-data:/var/lib/mysql es la clave. mysql-data es el nombre del volume (Docker lo crea solo) y /var/lib/mysql es el directorio de datos dentro del contenedor.
Comprueba que la persistencia funciona de verdad:
# Entra al contenedor y crea una base de datos
docker exec -it mysql-persistent mysql -uroot -prootpwd123 -e "CREATE DATABASE testdb;"
# Para y elimina el contenedor
docker stop mysql-persistent
docker rm mysql-persistent
# Vuelve a arrancar con el mismo volume
docker run --name mysql-persistent \
-e MYSQL_ROOT_PASSWORD=rootpwd123 \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
-d mysql:8.0
# Comprueba: testdb sigue ahí
docker exec -it mysql-persistent mysql -uroot -prootpwd123 -e "SHOW DATABASES;"
Si ves testdb, los datos se salvaron. Esa sensación da tranquilidad.
Montaje de configuración: parámetros personalizados de MySQL
Con la persistencia resuelta, el siguiente paso: ¿cómo cambiar la configuración de MySQL?
Por ejemplo, pasar el juego de caracteres a utf8mb4 o subir el máximo de conexiones. Sin montar un archivo de configuración, toca entrar al contenedor a mano cada vez y, al reiniciar, volver a empezar.
MySQL lee configuración adicional en /etc/mysql/conf.d/; basta con montar ahí tu my.cnf.
Crea el archivo en el host:
mkdir -p /home/mysql/conf
cat > /home/mysql/conf/my.cnf << 'EOF'
[mysqld]
# Juego de caracteres
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# Conexiones
max_connections=1000
# Plugin de autenticación (ayuda con algunos clientes)
default_authentication_plugin=mysql_native_password
[client]
default-character-set=utf8mb4
EOF
Arranca el contenedor montando ese archivo:
docker run --name mysql-custom \
-e MYSQL_ROOT_PASSWORD=rootpwd123 \
-p 3306:3306 \
-v /home/mysql/conf:/etc/mysql/conf.d \
-v /home/mysql/data:/var/lib/mysql \
-d mysql:8.0
Aquí montas dos cosas: configuración y datos.
Verifica que la configuración aplicó:
docker exec -it mysql-custom mysql -uroot -prootpwd123 -e "SHOW VARIABLES LIKE 'character%';"
Si character_set_server es utf8mb4, la configuración está activa.
Solucionar conexiones desde fuera del contenedor
El contenedor corre, los datos persisten y la config está montada. Conectas desde tu aplicación local y…
ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (Connection refused)
o
ERROR 1045 (28000): Access denied for user 'root'@'172.17.0.1'
Yo también me topé con estos dos errores y tardé un rato en entenderlos.
Problema 1: Connection refused
Casi siempre es el mapeo de puertos. Al arrancar el contenedor usa -p 3306:3306 para exponer el 3306 del contenedor en el host.
Si el 3306 del host ya está ocupado (por ejemplo, tienes MySQL instalado localmente), mapea otro puerto:
-p 3307:3306 # Accedes por 3307 en el host; dentro del contenedor sigue siendo 3306
Otra causa habitual es el firewall. En un servidor Linux:
# CentOS/RHEL
sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent
sudo firewall-cmd --reload
# Ubuntu
sudo ufw allow 3306/tcp
Problema 2: Access denied
Es un tema de permisos. MySQL crea root por defecto solo para localhost; desde otra IP no entra.
Solución: cambiar el host de root a % (cualquier IP):
# Entra al contenedor
docker exec -it mysql-custom mysql -uroot -prootpwd123
# Ejecuta este SQL
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'rootpwd123';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Dos matices:
- El plugin
mysql_native_passwordsuele ir mejor con clientes antiguos - En producción no hagas esto: no dejes que
rootconecte desde cualquier IP; crea usuarios dedicados y limita IPs
Tras el cambio, la aplicación externa debería conectar.
Con esto, el despliegue básico de MySQL en Docker en instancia única ya no debería darte grandes sorpresas.
Gestionar con Docker Compose de forma ordenada
Por qué recomendamos Docker Compose
Para desarrollo local, los docker run de antes bastan. En el día a día aparecen otros problemas:
- Comandos largos y difíciles de recordar
- Parámetros que se escriben mal (rutas de volume, etc.)
- En equipo, cada uno arranca distinto y la configuración se desordena
- Varios contenedores (MySQL + Redis + Nginx) y arrancarlos uno a uno es pesado
Ahí entra Docker Compose.
En la práctica, Compose mete esa cadena de docker run en un YAML. Arrancas con docker-compose up -d, paras con docker-compose down, y el archivo va al repositorio.
Un compañero nuevo pregunta «¿cómo levanto MySQL?» y le pasas el docker-compose.yml; clona, un comando y listo.
Configuración de MySQL en instancia única con Compose
Configuración completa, línea a línea:
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql-standalone
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpwd123
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppwd123
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./logs:/var/log/mysql
networks:
- mysql-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpwd123"]
interval: 10s
timeout: 5s
retries: 3
volumes:
mysql-data:
networks:
mysql-network:
driver: bridge
Detalle de lo importante:
environment:
MYSQL_ROOT_PASSWORD: contraseña de root, obligatoriaMYSQL_DATABASE: base que se crea al arrancarMYSQL_USERyMYSQL_PASSWORD: usuario normal (más seguro que root)
volumes:
mysql-data:/var/lib/mysql: persistencia con named volume./conf/my.cnf:/etc/mysql/conf.d/my.cnf: configuración con ruta relativa./logs:/var/log/mysql: logs en el host para depurar
restart: always: reinicio automático del contenedor y tras reiniciar el servidor
healthcheck: ping periódico a MySQL; si falla, reinicio
networks: red propia para que varios contenedores se hablen entre sí
Pasos de uso:
- Crea la estructura de carpetas:
mkdir -p mysql-docker/{conf,logs}
cd mysql-docker
- Crea
conf/my.cnf:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=1000
default_authentication_plugin=mysql_native_password
[client]
default-character-set=utf8mb4
-
Crea
docker-compose.yml(el de arriba) -
Arranca:
docker-compose up -d
- Estado:
docker-compose ps
Verás algo así:
Name Command State Ports
------------------------------------------------------------------------------------------------
mysql-standalone docker-entrypoint.sh mysqld Up (healthy) 0.0.0.0:3306->3306/tcp
Fíjate en (healthy): el healthcheck pasó.
- Logs:
docker-compose logs -f mysql
-f sigue el log en tiempo real, como tail -f. Si algo falla al arrancar, suele estar en los logs.
- Parar y quitar contenedores:
docker-compose down
Solo borra contenedores, no el volume (los datos siguen). Para borrar también los datos:
docker-compose down -v # ¡Cuidado! Borra todos los datos
En desarrollo local casi siempre uso Compose: configuras una vez y arrancar/parar es un comando.
Replicación maestro-esclavo lista para producción
Idea rápida de la replicación maestro-esclavo de MySQL
¿Para qué montar replicación?
MySQL en una sola máquina vale para proyectos pequeños; con más carga se queda corto. La replicación resuelve sobre todo dos cosas:
- Separación lectura/escritura: el maestro escribe (INSERT, UPDATE, DELETE) y los esclavos leen (SELECT). Muchas apps leen más de lo que escriben; repartir lecturas entre esclavos mejora el rendimiento
- Copia de seguridad y disponibilidad: si cae el maestro, el esclavo puede seguir sirviendo lecturas al menos
La idea es simple:
- El maestro (Master) activa binlog y registra cambios
- El esclavo (Slave) se conecta al maestro y lee el binlog
- En el esclavo, un hilo IO trae el binlog al relay log y un hilo SQL ejecuta esas sentencias
- Así los cambios del maestro llegan al esclavo
En Docker, básicamente:
- Dos contenedores con
server-iddistintos - Binlog activo en el maestro
- El esclavo se enlaza al maestro e inicia la replicación
Suena complejo, pero con Compose suele ser arrancar y listo.
Configuración del nodo Master
El maestro necesita: binlog, server-id y usuario de replicación.
- Archivo
conf/master.cnf:
[mysqld]
# ID único; maestro y esclavo no pueden repetirse
server-id=1
# Log binario
log-bin=mysql-bin
# Formato ROW: registra cambios fila a fila, más seguro
binlog-format=ROW
# Juego de caracteres
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# Opcional: bases a replicar (sin esto, todas)
# binlog-do-db=myapp
# Opcional: bases a excluir
# binlog-ignore-db=mysql
# binlog-ignore-db=information_schema
docker-composedel maestro:
version: '3.8'
services:
mysql-master:
image: mysql:8.0
container_name: mysql-master
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpwd123
MYSQL_DATABASE: myapp
ports:
- "3306:3306"
volumes:
- master-data:/var/lib/mysql
- ./conf/master.cnf:/etc/mysql/conf.d/master.cnf
- ./logs/master:/var/log/mysql
networks:
- mysql-replication
volumes:
master-data:
networks:
mysql-replication:
driver: bridge
- Arranca el maestro:
docker-compose up -d mysql-master
- Usuario de replicación:
docker exec -it mysql-master mysql -uroot -prootpwd123
-- Crear usuario de replicación
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'replpwd123';
-- Permisos de replicación
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
-- Estado del maestro: anota File y Position
SHOW MASTER STATUS;
SHOW MASTER STATUS devuelve algo como:
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 156 | | |
+------------------+----------+--------------+------------------+
Importante: guarda File y Position; los necesitas en el esclavo.
Configuración del nodo Slave
- Archivo
conf/slave.cnf:
[mysqld]
# ID único, distinto del maestro
server-id=2
# Relay log
relay-log=relay-bin
# Solo lectura en el esclavo (evita escrituras accidentales)
read-only=1
# Juego de caracteres
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
- Añade el esclavo al
docker-compose.yml:
version: '3.8'
services:
mysql-master:
image: mysql:8.0
container_name: mysql-master
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpwd123
MYSQL_DATABASE: myapp
ports:
- "3306:3306"
volumes:
- master-data:/var/lib/mysql
- ./conf/master.cnf:/etc/mysql/conf.d/master.cnf
- ./logs/master:/var/log/mysql
networks:
- mysql-replication
mysql-slave:
image: mysql:8.0
container_name: mysql-slave
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpwd123
ports:
- "3307:3306" # En el host accedes al esclavo por 3307
volumes:
- slave-data:/var/lib/mysql
- ./conf/slave.cnf:/etc/mysql/conf.d/slave.cnf
- ./logs/slave:/var/log/mysql
networks:
- mysql-replication
depends_on:
- mysql-master
volumes:
master-data:
slave-data:
networks:
mysql-replication:
driver: bridge
- Arranca el esclavo:
docker-compose up -d mysql-slave
- Enlaza el esclavo al maestro:
docker exec -it mysql-slave mysql -uroot -prootpwd123
-- Conexión al maestro (sustituye File y Position por los tuyos)
CHANGE MASTER TO
MASTER_HOST='mysql-master', -- Nombre del contenedor maestro en la red Docker
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='replpwd123',
MASTER_LOG_FILE='mysql-bin.000003', -- De SHOW MASTER STATUS
MASTER_LOG_POS=156; -- De SHOW MASTER STATUS
START SLAVE;
SHOW SLAVE STATUS\G
Verificar la sincronización maestro-esclavo
En SHOW SLAVE STATUS\G mira sobre todo:
Slave_IO_Running: Yes # Hilo IO; debe ser Yes
Slave_SQL_Running: Yes # Hilo SQL; debe ser Yes
Seconds_Behind_Master: 0 # Retraso en segundos; 0 = en tiempo real
Last_IO_Error: # Vacío = bien
Last_SQL_Error: # Vacío = bien
Si Slave_IO_Running y Slave_SQL_Running son Yes, la replicación está activa.
Prueba real:
- Datos en el maestro:
docker exec -it mysql-master mysql -uroot -prootpwd123 -e "
USE myapp;
CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO test_table VALUES (1, 'test data');
"
- Consulta en el esclavo:
docker exec -it mysql-slave mysql -uroot -prootpwd123 -e "
USE myapp;
SELECT * FROM test_table;
"
Si ves la fila insertada, la sincronización funciona.
Depuración de problemas frecuentes
La primera vez suele haber tropiezos. Los más habituales:
Problema 1: Slave_IO_Running es No
Posibles causas:
- Red: comprueba que comparten red;
docker exec -it mysql-slave ping mysql-master - Usuario
replmal creado o sin permisos MASTER_LOG_FILEoMASTER_LOG_POSincorrectos: vuelve aSHOW MASTER STATUS
Problema 2: Slave_SQL_Running es No
Posibles causas:
- Error SQL: mira
Last_SQL_Error - Datos distintos entre maestro y esclavo: si el maestro ya tenía datos, exporta del maestro, importa en el esclavo y luego configura replicación
Problema 3: Seconds_Behind_Master siempre alto
Posibles causas:
- Esclavo con pocos recursos: CPU, RAM, disco
- Mucha escritura en el maestro: más esclavos
- Red lenta: revisa latencia
Si no avanzas, reinicia la configuración del esclavo:
-- En el esclavo
STOP SLAVE;
RESET SLAVE;
-- Vuelve a CHANGE MASTER TO y START SLAVE
Optimización de rendimiento y buenas prácticas
Recomendaciones de rendimiento para MySQL en Docker
Muchos temen que Docker ralentice MySQL. Hace años era más cierto; en 2024 el impacto suele quedar por debajo del 5 % y en cargas intensivas de I/O casi no se nota.
Aun así, conviene optimizar:
1. Tipo de volume
- named volume: Docker elige el driver; cómodo en desarrollo
- bind mount: directorio del host; mejor en producción (backup y monitorización)
# named volume
volumes:
- mysql-data:/var/lib/mysql
# bind mount
volumes:
- /data/mysql:/var/lib/mysql
2. Modo de red
La red bridge por defecto suele bastar. Si buscas el máximo rendimiento, prueba host:
services:
mysql:
network_mode: "host" # Red del host; mejor rendimiento
Con host no hace falta ports; el contenedor escucha directamente el 3306 del host.
3. Límites de recursos
En producción limita recursos para que MySQL no se coma el servidor:
services:
mysql:
image: mysql:8.0
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
memory: 1G
Necesitas docker-compose --compatibility up o Docker Swarm.
4. Gestión de logs
Sin límite, los logs del contenedor pueden llenar el disco:
services:
mysql:
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"
Lista de buenas prácticas en producción
Resumen de lo que aprendí a base de errores.
Seguridad:
- No uses contraseñas por defecto o débiles
# ❌ No hagas esto
MYSQL_ROOT_PASSWORD: 123456
# ✅ Contraseña fuerte o Docker secrets
MYSQL_ROOT_PASSWORD: "Mx8#kL9$pQ2@vN4!"
- Docker secrets para datos sensibles
services:
mysql:
image: mysql:8.0
secrets:
- mysql_root_password
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
secrets:
mysql_root_password:
file: ./secrets/mysql_root_password.txt
- Restringir acceso de red
networks:
mysql-network:
driver: bridge
internal: true # Solo entre contenedores, sin acceso externo
Si hace falta acceso externo, usa un contenedor de aplicación como proxy; no expongas MySQL directamente.
Operaciones:
- Backup periódico del directorio de datos
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
docker exec mysql-master mysqldump -uroot -prootpwd123 --all-databases > backup_$DATE.sql
# O backup del directorio de datos
tar -czf mysql-data-backup_$DATE.tar.gz /data/mysql/
En producción, backup diario automático y al menos 7 días de retención.
- Healthcheck para monitorizar
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
Reinicio automático si cae; mejor con alertas.
- Volume aparte para logs
volumes:
- ./logs:/var/log/mysql
Logs fuera del volume de datos: más fácil depurar y no llenas los datos.
Alta disponibilidad:
- Al menos un maestro y un esclavo; a menudo un maestro y varios esclavos
Con mucha lectura, 3–5 esclavos reparten SELECT.
- Balanceo para lectura/escritura
MySQL Router, ProxySQL o lógica en la aplicación:
- Escritura (INSERT/UPDATE/DELETE) → maestro
- Lectura (SELECT) → esclavos con balanceo
- Prueba periódica del failover
No esperes a que caiga el maestro para descubrir que el esclavo no sirve:
-- En el esclavo
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only=0; -- Quita solo lectura y promueve a maestro
En producción, soluciones maduras (MHA, Orchestrator) para conmutación automática.
Conclusión
Repasemos lo esencial.
Desde el despliegue básico de MySQL en Docker, persistencia, montaje de configuración y conexión externa, hasta Docker Compose y replicación maestro-esclavo en producción: este flujo cubre los escenarios habituales.
Puntos clave:
- La persistencia es obligatoria; no corras MySQL en un contenedor «desnudo»
- Monta la configuración; juego de caracteres y conexiones conviene dejarlos listos desde el principio
- Docker Compose es la norma; configuración centralizada y mejor para el equipo
- La replicación no es tan difícil; lo crítico es el archivo de config y el orden de los pasos
- En producción, seguridad y backups; contraseñas fuertes y copias regulares
Todo el código de configuración de este artículo lo he probado y puedes copiarlo a tu proyecto cambiando contraseñas y puertos.
Si es tu primera vez con MySQL en Docker, empieza por instancia única: entiende persistencia y montaje de config antes de la replicación. Paso a paso.
Si algo falla, en los logs suele estar la pista. Si te atasacas, comenta y respondo cuando pueda.
Docker para MySQL suele ser mucho más cómodo que el despliegue tradicional: configuras una vez y corre en cualquier sitio.
Flujo completo de despliegue de MySQL con Docker
Desde la persistencia de datos hasta la replicación maestro-esclavo: soluciona pérdida de datos al reiniciar, montaje de configuración y fallos de conexión
⏱️ Estimated time: 1 hr
- 1
Step 1: Despliegue en instancia única: persistencia y montaje de configuración
Persistencia de datos:
• Monta el directorio de datos con Volume:
docker run -d -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
• Montaje de archivo de configuración:
docker run -d -v mysql-data:/var/lib/mysql -v ./my.cnf:/etc/mysql/conf.d/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
• Variables de entorno:
MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD
Verificar persistencia:
• Tras eliminar y recrear el contenedor, los datos siguen ahí - 2
Step 2: Configuración de replicación maestro-esclavo
Configurar el maestro:
• Activar binlog: en my.cnf configurar log-bin=mysql-bin
• Definir server-id: server-id=1
• Crear usuario de replicación:
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Configurar el esclavo:
• Indicar la dirección del maestro:
CHANGE MASTER TO
MASTER_HOST='master',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
• Iniciar replicación: START SLAVE;
• Verificar estado: SHOW SLAVE STATUS\G; - 3
Step 3: Solución de problemas comunes y despliegue en producción
Problemas frecuentes:
• Fallo de conexión: revisar mapeo de puertos -p 3306:3306, red y firewall
• Pérdida de datos: configurar persistencia con Volume
• Juego de caracteres: en my.cnf character-set-server=utf8mb4
• Permisos: revisar permisos del Volume chmod 755
Despliegue en producción:
• Gestionar varios contenedores con docker-compose
• Configurar healthcheck
• Límites de recursos (deploy.resources)
• Estrategia de copias de seguridad (backup periódico del Volume)
• Usar Volume con nombre para facilitar la gestión
FAQ
¿Cómo evitar la pérdida de datos al desplegar MySQL con Docker?
1) Montar el directorio de datos con Volume:
docker run -d -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
2) Montaje de archivo de configuración:
docker run -d -v mysql-data:/var/lib/mysql -v ./my.cnf:/etc/mysql/conf.d/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
3) Variables de entorno:
• MYSQL_ROOT_PASSWORD
• MYSQL_DATABASE
• MYSQL_USER
• MYSQL_PASSWORD
Verificar persistencia: elimina el contenedor y créalo de nuevo; los datos siguen ahí.
Causa raíz:
Al reiniciar el contenedor se pierden los datos porque Docker guarda los datos en la capa del contenedor por defecto; al borrar el contenedor desaparecen. Hay que configurar persistencia.
¿Cómo configurar la replicación maestro-esclavo de MySQL?
1) Activar binlog (en my.cnf: log-bin=mysql-bin)
2) Definir server-id (server-id=1)
3) Crear usuario de replicación:
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Configurar el esclavo:
1) Indicar la dirección del maestro:
CHANGE MASTER TO
MASTER_HOST='master',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
2) Iniciar replicación: START SLAVE;
3) Verificar estado: SHOW SLAVE STATUS\G;
¿Cómo solucionar fallos de conexión a MySQL en Docker?
• Fallo de conexión: revisar mapeo de puertos -p 3306:3306, red y firewall
• Pérdida de datos: configurar persistencia con Volume
• Juego de caracteres: en my.cnf character-set-server=utf8mb4
• Permisos: revisar permisos del Volume chmod 755
Pasos de comprobación:
1) Confirmar que el contenedor está en ejecución (docker ps)
2) Revisar mapeo de puertos (docker port container-name)
3) Revisar la red (docker network inspect network-name)
4) Ver logs del contenedor (docker logs container-name)
14 min de lectura · Publicado el: 18 dic 2025 · Actualizado el: 21 ago 2026
Guía práctica de Docker
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Guía completa para desplegar Redis con Docker: persistencia y autenticación por contraseña
Tutorial paso a paso para desplegar Redis con Docker y configurar persistencia RDB/AOF y autenticación por contraseña, evitando pérdida de datos al reiniciar el contenedor. Con archivos de configuración completos y ejemplos de código para producción
Parte 26 de 38
Siguiente
Guía completa para desplegar Nginx con Docker: montaje de configuración, HTTPS y proxy inverso
Tutorial completo: montaje de archivos de configuración, certificados HTTPS y proxy inverso al desplegar Nginx con Docker. Soluciona problemas habituales como configuración que no se aplica y comunicación entre contenedores, con renovación automática de Let's Encrypt y mejores prácticas para producción.
Parte 28 de 38



Comentarios
Inicia sesión con GitHub para dejar un comentario