必须先定位宿主机原MySQL的datadir路径(如/var/lib/mysql),停库后校验权限、版本兼容性及lower_case_table_names配置,再以绝对路径挂载到Docker容器的/var/lib/mysql,确保镜像版本不低于原版且属主匹配(如999:999)。
必须先定位宿主机上原MySQL的datadir,否则后续挂载会失败。执行mysql --help | grep "datadir"或查看/etc/my.cnf中的datadir配置项。常见路径是/var/lib/mysql,但生产环境可能自定义为/data/mysql或/opt/mysql/data。别直接假设路径——用mysqld --verbose --help | grep "datadir"验证更稳妥。
迁移前必须停止原MySQL服务:systemctl stop mysqld(或service mysql stop)。接着检查两件事:
datadir下所有文件属主是否为mysql:mysql(Docker内MySQL进程默认以mysql用户运行);若不是,宿主机上需chown -R mysql:mysql /path/to/old/datadir
mysqld --version),新Docker镜像版本不能低于旧版(例如旧版5.7,不可用8.0镜像直接挂载数据目录,会因ibdata1格式不兼容启动失败)my.cnf中lower_case_table_names值,Docker容器内外必须一致,否则表名识别异常不要用docker commit或mysqldump导入——那是逻辑迁移,本文目标是物理目录映射。关键命令结构如下:
docker run -d --name mysql-migrated -p 3306:3306 -v /path/on/host:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=yourpass -e TZ=Asia/Shanghai mysql:5.7
注意三点:
/path/on/host必须是宿主机上原datadir的**绝对路径**,且该目录下应包含ibdata1、ib_logfile*、mysql、performance_schema等原始文件夹/文件mysql:5.7),避免版本越级/etc/mysql/conf.d/或/var/run/mysqld等配套目录,否则容器可能报错退出容器反复重启或docker logs mysql-migrated显示Can't start server : Bind on unix socket或InnoDB: Unable to lock ./ibdata1,大概率是以下原因:
ibdata1被原MySQL进程残留锁住:确认systemctl is-active mysqld返回inactive,再lsof /path/to/old/datadir/ibdata1清空占用docker exec -it mysql-migrated ls -l /var/lib/mysql,看文件属主是否为999:999(MySQL 5.7官方镜像默认uid/gid);若宿主机原目录属主是27:27,需提前chown -R 999:999 /path/on/host
setenforce 0临时关闭,或chcon -Rt svirt_sandbox_file_t /path/on/host
物理目录迁移本质是复用InnoDB存储引擎的原始文件,任何一点元数据不匹配都会导致启动失败——它不像SQL导入那样容错,必须严格对齐版本、权限、配置三要素。