一、背景说明
在使用 Dokploy(或 Coolify / Docker Compose)部署应用(如 Halo、Typecho、WordPress)时,
很多人以为 “我已经在 compose 里写了 volume,数据就一定安全”。
但实际上:
即使你声明了 volume,如果没有使用 external volume,数据仍然可能和项目绑定。
当你:
- 删除 Dokploy 项目
- 重建项目(项目名变化)
- 迁移到新项目
就会出现一个非常诡异的现象:
数据明明还在磁盘上,但新容器却“像是全新安装”。
二、问题现象(典型)
你在 compose 中写了:
volumes:
- halo_server_data:/root/.halo
volumes:
halo_server_data:
然后你在服务器上看到真实路径是:
/var/lib/docker/volumes/
└── web-haloserver-nf8kxo_halo_server_data/_data
接着你删除 Dokploy 项目,重新创建一个新项目。
👉 新项目启动后,Halo 变成了全新初始化状态。
三、问题根因(非常关键)
1️⃣ Docker Compose 的真实行为
即使你在 compose 里写了:
volumes:
halo_server_data:
Docker 实际创建的 volume 名字是:
<project_name>_halo_server_data
例如:
web-haloserver-nf8kxo_halo_server_data
也就是说:
这个 volume 并不是全局唯一的,而是“项目私有”的。
2️⃣ Dokploy 的“隐形前缀”问题
Dokploy 会自动生成 project name(如 web-haloserver-nf8kxo),
你在 UI 中是看不到这个前缀的。
结果就是:
- 项目一删
- 项目名一变
- 新项目引用的是一个全新的 volume
而旧数据则变成了“孤儿 volume”。
四、正确的解决方案:使用 external volume + 稳定名字
核心原则
生产环境的数据 volume,必须脱离项目生命周期。
这就需要使用 external volume。
五、创建一个“稳定名字”的 Volume(只需一次)
docker volume create halo_server_data
这个 volume 的真实路径是:
/var/lib/docker/volumes/halo_server_data/_data
六、正确的 Docker Compose 写法(重点)
services:
halo_server:
image: halohub/halo:1.6.1
restart: unless-stopped
volumes:
- halo_server_data:/root/.halo
volumes:
halo_server_data:
external: true
name: halo_server_data
这两行的意义:
external: true
name: halo_server_data
含义是:
- 这个 volume 已经存在
- 不要给它加项目名前缀
- 不要随项目删除
七、如何从“旧项目 volume”迁移数据(安全步骤)
假设你当前的数据在:
web-haloserver-nf8kxo_halo_server_data
而你已经创建了新的稳定 volume:
halo_server_data
使用以下命令迁移数据(推荐)
docker run --rm \
-v web-haloserver-nf8kxo_halo_server_data:/from \
-v halo_server_data:/to \
alpine cp -a /from/. /to/
说明:
-a:保留权限和结构/from/.:确保拷贝所有隐藏文件
八、迁移完成后的检查
docker volume ls
你应该看到:
local halo_server_data
并且 不再依赖任何 web-xxx_ 前缀的 volume。
九、最佳实践总结(强烈建议)
✅ 必须做的
-
所有生产数据使用
external volume -
volume 名字使用稳定、语义化命名
halo_datapostgres_dataredis_data
❌ 避免做的
- 依赖 Dokploy 自动生成的 volume
- 使用带项目名前缀的 volume 作为长期数据
- 删除项目之前不确认 volume 类型
十、一句话总结
没有
external: true的 Docker Volume,
在 Dokploy 中只是“暂时安全”,不是“长期安全”。
评论区