docker volume create 创建的是空命名卷,不会自动迁移原容器数据;必须先停用原容器,再通过 docker cp 或临时容器手动将可写层数据复制到新卷中。

docker volume create 是把临时容器数据迁移到数据卷的第一步,但直接创建卷并挂载不会自动恢复原有数据——你得手动搬。
docker volume create 创建命名卷后,原容器数据不会自动迁移
命名卷是空的,哪怕你用相同路径(比如 /var/lib/mysql)挂载进去,里面也不会有旧数据。
常见错误现象:
- 容器删了重跑,加了
-v mysql-data:/var/lib/mysql,结果 MySQL 启动失败或数据库为空 -
docker volume inspect mysql-data显示Mountpoint下是空目录
这是因为:
- Docker 只在首次挂载空卷时,把镜像里对应路径的文件复制进去(仅一次)
- 你原来的容器数据在可写层,根本没进过卷,Docker 不知道它存在
所以必须人工介入。实操建议:
- 先停掉原容器:
docker stop myapp - 启动一个临时容器,把原容器可写层数据打包出来:
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):/backup alpine tar -cf /backup/old-data.tar -C /var/lib/docker/containers/$(docker inspect myapp -f '{{.Id}}')/mounts/shm .(不推荐,路径太绕) - 更稳妥的做法:用
docker commit把原容器打成镜像,再docker create临时容器导出数据
用 docker cp 从运行中容器提取数据到宿主机再导入卷
这是最直接、适合 Docker Desktop 用户的方式,不需要碰 /var/lib/docker 路径(Windows/macOS 上不可见或权限受限)。
步骤:
- 确保目标容器还在运行(或至少是
created状态):docker start myapp - 找到你要持久化的路径,比如应用日志在
/app/logs,配置在/app/conf - 拷贝出来:
docker cp myapp:/app/logs ./logs-backup - 创建命名卷:
docker volume create app-logs - 启动新容器并挂载:
docker run -d --name myapp-new -v app-logs:/app/logs -v ./logs-backup:/tmp/restore myimage - 进入新容器把数据挪进去:
docker exec myapp-new sh -c "cp -r /tmp/restore/* /app/logs/"
注意点:
-
docker cp不支持直接拷贝到命名卷,只能先到宿主机再中转 - macOS 上 Docker Desktop 的
~路径需显式写成$HOME或绝对路径,否则可能失败 - 如果原路径权限是
root,新容器里用户可能没权限写,建议启动时加--user root或提前chown
docker run --volumes-from 不适用于 Docker Desktop 的“迁移”场景
这个参数本意是让新容器复用另一个容器的挂载配置,但它不复制数据,也不关联命名卷。
典型误用:
-
docker run -d --name old --volume /data busybox sleep 3600 -
docker run --volumes-from old -v newvol:/data2 alpine ls /data2→ 结果是空的
原因:
-
--volumes-from只继承挂载点定义,不是数据源 - Docker Desktop 的 Linuxkit VM 层对这种跨容器挂载支持不稳定,尤其在 Windows/macOS 上容易挂载失败或只读
所以别指望靠它“迁移”。真要共享,就用同一个命名卷名,比如两个容器都挂 -v app-data:/app/data。
真正麻烦的不是命令怎么写,而是搞清数据在哪、谁在读写、权限是否匹配。Docker Desktop 的图形界面看着友好,但底层仍是 Linux 容器引擎,/var/lib/docker 被封装在 VM 里,你没法直接 ls 它——这意味着所有迁移动作都得通过容器内操作或 docker cp 中转,不能图省事跳过验证步骤。











