mysql-bind-mount-to-named-volume-migration

Docker Compose:MySQL 从绑定目录改为命名卷后「数据不见了」?迁移与选型说明

适用场景:原先使用 ./data/mysql:/var/lib/mysql 持久化,后来改为 mysql-data:/var/lib/mysql命名卷,发现库里没有以前的库表。本文说明原因,并给出两种通用解决方案(迁移进卷 / 改回绑定目录),可直接用于团队文档或技术博文。


一、现象

  • 修改 docker-compose.yml 后,MySQL 能正常启动。
  • 但登录后发现:以前的数据库、表都不见了,像刚装好的新实例。
  • 宿主机上 ./data/mysql(或你原来的目录)里明明还有一堆文件

二、原因(核心一句话)

绑定挂载(bind mount)和命名卷(named volume)是两套不同的存储位置。

改配置后,新容器读写的是新位置 (例如空的 mysql-data 卷),不会自动 去用你旧的 ./data/mysql,所以旧数据「看起来丢了」,其实仍在原目录里。

挂载方式 数据实际在哪
./data/mysql:/var/lib/mysql 宿主机你指定的目录(如项目下 data/mysql
mysql-data:/var/lib/mysql Docker 管理的卷(docker volume ls 里能看到,路径由 Docker 决定)

MySQL 官方镜像只在数据目录为空 时执行 docker-entrypoint-initdb.d 里的初始化脚本;若命名卷是新的空卷,还会再跑一遍初始化,进一步让你感觉「全是新的」。


三、方案 A:把旧数据迁移进命名卷(推荐继续用命名卷时)

目标 :保留 mysql-data:/var/lib/mysql 的配置,把原 ./data/mysql 里的内容拷进该卷。

前置条件

  • MySQL 已停止(避免拷贝过程中文件被写坏)。
  • 旧数据与当前镜像 MySQL 大版本一致(例如都是 8.0),跨大版本直接拷数据目录风险高,应用备份/逻辑导出迁移。
  • 若命名卷里已经跑过一次 MySQL、生成了新数据,且你要以旧数据为准,通常需要先处理空卷(见下)。

操作步骤(Linux / macOS / Git Bash)

在项目根目录(docker-compose.yml 所在目录)执行:

bash 复制代码
# 1. 停止 MySQL
docker compose stop mysql

# 2. 查看卷名(Compose 会加项目前缀,常见为 目录名_mysql-data)
docker volume ls

# 3. 若确定要用旧数据完全覆盖卷内内容,且卷可删(注意:会删掉卷里当前所有内容)
# docker volume rm <项目前缀>_mysql-data
# 若删不掉,先:docker compose rm -f mysql

# 4. 将宿主机旧数据目录拷入命名卷(把 VOLUME_NAME 换成上一步看到的全名)
docker run --rm \
  -v VOLUME_NAME:/to \
  -v "$(pwd)/data/mysql:/from:ro" \
  alpine sh -c "cp -a /from/. /to/"

# 5. 启动 MySQL
docker compose up -d mysql

Windows PowerShell(Docker Desktop)

项目根目录 执行,VOLUME_NAME 替换为 docker volume ls 中的实际名称(例如 devops-core_mysql-data):

powershell 复制代码
docker compose stop mysql

docker volume ls

docker run --rm `
  -v "VOLUME_NAME:/to" `
  -v "${PWD}/data/mysql:/from:ro" `
  alpine sh -c "cp -a /from/. /to/"

docker compose up -d mysql

验证

bash 复制代码
docker compose exec mysql mysql -u root -p -e "SHOW DATABASES;"

应能看到迁移前的库名。

注意事项

  • 拷贝前尽量保证旧库是正常关闭后的数据目录;异常宕机后的目录可能需要 InnoDB 恢复,以日志为准。
  • 不要把不同机器、不同小版本混用 不经测试;生产环境更建议:mysqldump 逻辑备份 → 新实例导入

四、方案 B:改回绑定目录(零迁移,立刻用回旧数据)

目标 :不再使用命名卷,继续用 ./data/mysql:/var/lib/mysql

docker-compose.yml 中把:

yaml 复制代码
volumes:
  - mysql-data:/var/lib/mysql

改回:

yaml 复制代码
volumes:
  - ./data/mysql:/var/lib/mysql

并在文件底部 volumes: 声明块 里删除不再使用的 mysql-data:(若没有其他服务引用)。

然后:

bash 复制代码
docker compose up -d mysql

数据会立刻从原 ./data/mysql 读取,无需拷贝

注意 :之后请始终在同一项目根目录 执行 docker compose,避免相对路径 ./data/mysql 指向别的位置。


五、选型建议(方便写进团队规范)

需求 更合适的做法
数据要跟项目目录放一起、方便备份/拷贝 绑定挂载 ./data/mysql
避免「换目录执行 compose 导致换了一套数据」、与平台无关 命名卷 mysql-data
已用命名卷但历史数据在旧目录 方案 A 迁移,或方案 B改回

六、一句话总结

改挂载 = 换磁盘;旧数据不会自动跟过去。

要么把旧目录拷进新卷 (方案 A),要么继续挂载旧目录(方案 B)。


版权声明与转载

本文为通用运维说明,可根据需要修改示例路径、卷名后用于内部 Wiki 或公开技术博客;转载时注明出处即可。

相关推荐
PaperData13 小时前
1988-2025年《中国人口和就业统计年鉴》全年份excel+PDF
数据库·人工智能·数据分析·经管
星河耀银海14 小时前
C语言与数据库交互:SQLite实战与数据持久化
c语言·数据库·sqlite·交互
过期动态14 小时前
MySQL中的约束
android·java·数据库·spring boot·mysql
程序员陆通14 小时前
月烧 400 刀到不到 20 刀:我是怎么把 OpenClaw 的 Token 账单砍掉 95% 的
java·前端·数据库
Shan120514 小时前
站在计算机领域视角看:SQL注入攻击
网络·数据库·sql
轻刀快马15 小时前
别干背八股文了:从一场“双十一秒杀”惨案,看懂 InnoDB 事务、锁与索引的底层齿轮
数据库·sql
万事大吉CC15 小时前
【1】Django 基础:MTV 架构与核心组件
数据库·架构·django
曾凡宇先生15 小时前
mysql局域网授权
数据库·mysql
xcLeigh16 小时前
IoTDB Rust 原生接口开发指南:从零生成 + 完整 RPC 调用
数据库·rpc·rust·接口·api·时序数据库·iotdb
努力努力再努力wz16 小时前
【MySQL 进阶系列】拒绝滥用root:从 mysql.user 到权限校验,带你彻底理解用户管理与授权机制!
android·c语言·开发语言·数据结构·数据库·c++·mysql