平滑迁移mysql数据需三步:先停容器、验旧数据完整性与权限、确认新卷干净;再用alpine临时容器原子化拷贝;最后分步启动验证库表存在且可读写,并清理旧挂载、配置volume备份。

直接改配置会导致数据“消失”,是因为 Bind Mount 和命名 Volume 是两套互不感知的存储路径。平滑迁移的关键不是跳过旧数据,而是让新卷承载旧数据,同时避免服务中断和权限错乱。
迁移前必须确认的三件事
确保操作安全,先验证以下三点:
-
MySQL 容器已完全停止:用
docker compose stop mysql或docker stop <container_name></container_name>,不能只kill -15或依赖健康检查假死 -
宿主机旧数据目录可读且结构完整:进入
./data/mysql(或你原来的挂载路径),确认有ibdata1、mysql/、performance_schema/等核心文件/目录,且属主不是 root(推荐为999:999或镜像内 MySQL 用户 UID/GID) -
新命名卷尚未被初始化过数据:运行
docker volume inspect mysql-data,若返回中CreatedAt很新、且Mountpoint下为空或只有lost+found,说明是干净卷;若已有数据且需覆盖,先docker volume rm mysql-data(注意:此操作不可逆)
用临时容器完成原子化拷贝
不进宿主机深层路径,也不手动 chown,靠 Alpine 镜像 + 双挂载实现零权限失真迁移:
- 执行命令(在
docker-compose.yml同级目录运行):docker run --rm \<br> -v mysql-data:/to \<br> -v "$(pwd)/data/mysql:/from:ro" \<br> alpine:latest sh -c "cp -a /from/. /to/"
- 关键点:
•-v mysql-data:/to挂载目标卷到容器内/to
•-v "$(pwd)/data/mysql:/from:ro"只读挂载旧数据,防止误写
•cp -a保留所有属性(权限、时间戳、符号链接)
启动新容器并验证一致性
改完 docker-compose.yml 后,不要直接 up -d,分步验证:
- 先以非后台模式启动,观察日志:
docker compose run --rm --service-ports mysql
看到MySQL init process done. Ready for start up.且无Initializing database提示,说明未触发初始化脚本(即数据已就位) - 进容器检查数据:
docker compose exec mysql mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "SHOW DATABASES;"
应完整列出你原有的库名(如app_db、monitoring),而非只有information_schema和mysql - 连业务应用跑一个简单查询(如
SELECT COUNT(*) FROM users LIMIT 1;),确认可读可写
收尾与加固建议
迁移完成后,建议做两件事提升长期稳定性:
-
删掉旧绑定目录的残留引用:检查
docker-compose.yml中是否还有./data/mysql字样(包括注释),彻底清除歧义 -
为 Volume 配置备份策略:命名 Volume 支持
docker run --rm -v mysql-data:/data -v $(pwd)/backup:/backup alpine tar czf /backup/mysql-$(date +%F).tar.gz -C /data .,比 Bind Mount 更易集成 CI/CD 备份流水线










