环境: 飞牛 OS(fnOS,基于 Debian)+ 1Panel v2.2.1 + Docker
目标: 将 Docker 数据从系统盘迁移至数据盘,彻底释放系统盘空间
结果: 系统盘占用从 41%(11G)降至 25%(6.3G),释放约 5G
一、背景与起因
在飞牛 OS 上通过 1Panel 管理 Docker 应用(Halo 博客、Nginx Proxy Manager、frpc、MCSManager 等),运行一段时间后发现系统盘空间持续增长,担心未来被写满引发服务中断,而且中途已经发生过一次系统盘占用拉满的情况了。
飞牛 OS 的存储架构
飞牛 OS 采用系统盘与数据盘物理分离的设计:
- 系统盘(
/dev/mmcblk0p2):28G eMMC,挂载于/,用于系统文件 - 数据盘
/vol1:120G,飞牛 OS 原本规划的 Docker 存储位置 - 数据盘
/vol2:205G,其他数据存储
问题根源
通过排查发现,飞牛 OS 原本将 Docker 数据存放在 /vol1/docker,但 1Panel 安装后将 Docker 的 data-root 重置回了默认的 /var/lib/docker(系统盘),导致之后所有新拉取的镜像、容器层都写入系统盘,而 /vol1/docker 里只保留了飞牛 OS 时代的旧镜像。
# 排查命令:确认 Docker 实际使用的目录
sudo docker info | grep "Docker Root Dir"
# 输出:Docker Root Dir: /var/lib/docker ← 在系统盘,问题所在
# 查看各目录占用
sudo du -sh /var/lib/docker/overlay2 # 镜像层,最大头(显示 16G,实际因硬链接约 10G)
sudo du -sh /var/lib/docker/volumes # Docker 管理的卷
sudo du -sh /opt/1panel/apps # 1Panel 应用数据(bind mount)
关于 du 显示 16G 但系统盘只用 11G 的原因
du 统计文件内容大小,overlay2 中大量使用了硬链接——多个镜像层共享同一文件,du 会对每个硬链接都计一遍,导致数值虚高。实际磁盘占用以 df 为准。
二、核心操作:修改 Docker data-root
解决思路
只需将 daemon.json 中的 data-root 指回飞牛 OS 原本规划的 /vol1/docker,不需要重装 1Panel,不需要迁移任何数据。
操作步骤
第一步:停止 1Panel 和 Docker
sudo 1pctl stop
sudo systemctl stop docker
sudo systemctl stop docker.socket
sudo systemctl stop docker # 再执行一次确保完全停止
⚠️ 注意:飞牛 OS 的 1Panel 不能用
systemctl stop 1panel,要用1pctl stop
第二步:修改 daemon.json,加入 data-root
# 先查看现有配置,保留原有镜像源配置
sudo cat /etc/docker/daemon.json
# 写入新配置(保留原有镜像源,加入 data-root)
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://proxy.1panel.live",
"https://docker.m.daocloud.io",
"https://docker.nju.edu.cn",
"https://mirror.iscas.ac.cn"
// 保留你原有的所有镜像源
],
"data-root": "/vol1/docker"
}
EOF
# 验证 JSON 格式正确
sudo cat /etc/docker/daemon.json | python3 -m json.tool
第三步:启动 Docker 并验证
sudo systemctl start docker
# 必须确认路径已切换
sudo docker info | grep "Docker Root Dir"
# 应输出:Docker Root Dir: /vol1/docker
# 确认容器和镜像可见
sudo docker ps -a
sudo docker images
第四步:启动 1Panel
sudo 1pctl start
三、踩到的坑与处理方式
坑 1:1panel-network 网络丢失,Halo 无法连接 PostgreSQL
现象: 切换 data-root 后,Halo 启动报错:
Caused by: java.net.UnknownHostException: postgresql
Cannot connect to postgresql/<unresolved>:5432
原因: Docker 切换 data-root 后,原来在 /var/lib/docker 里的 1panel-network 自定义网络配置丢失,容器之间无法通过容器名互相解析。
处理方式:
# 确认网络是否存在
sudo docker network ls | grep 1panel
> ⚠️ 注意:如果网络存在,但是依然无法打开应用的web界面的话可以重启机器再试试。
# 如果不存在,重新创建,如果存在,不执行此步骤
sudo docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
1panel-network
然后在 1Panel 应用商店 → 已安装,对所有应用点**「重建」**(注意是重建不是重启),让容器重新加入网络。
✅ 本次操作中
1panel-network实际上已经在/vol1/docker里存在,直接启动 1Panel 后网络自动恢复,未受影响。
坑 2:部分应用镜像丢失,重建时需要重新拉取
现象: NPM、Hermes 等应用点重建后一直卡住,或提示找不到镜像。
原因: 这些镜像是在 1Panel 安装后才拉取的,存在系统盘 /var/lib/docker 里,切换到 /vol1/docker 后自然看不到了。/vol1/docker 里只有飞牛 OS 时代的旧镜像(包括一些早已"卸载"但镜像残留的应用,如 qwrt)。
处理方式:
在 1Panel 界面 → 容器 → 镜像 → 手动拉取缺失的镜像,利用已配置的加速源下载。镜像拉取完成后再启动对应应用。
优先从1panel界面拉取镜像,拉取成功之后,正常情况可以在应用界面直接启动应用。
# 也可以命令行直接启动,会自动拉取镜像
cd /opt/1panel/apps/nginx-proxy-manager/nginx-proxy-manager
sudo docker compose up -d
cd /opt/1panel/apps/hermes-agent/Hermes-Agent
sudo docker compose up -d
💡 更优方案(如果网络好): 切换前先把系统盘的新镜像 rsync 合并到
/vol1/docker,避免重新下载:sudo rsync -aHAX /var/lib/docker/ /vol1/docker/本次因为数据量不大、网络速度可接受,选择了直接重新拉取。
坑 3:NPM 重建卡死,容器未创建成功,该情况是应用镜像丢失导致的
现象: 1Panel 界面显示"重建中"但长时间没有进度,docker ps -a 里找不到 NPM 容器。
处理方式: 绕过 1Panel 的重建流程,直接用 docker compose 手动启动:
# 找到 compose 文件位置
sudo find /opt -name "docker-compose.yml" 2>/dev/null | grep nginx
# 直接启动
cd /opt/1panel/apps/nginx-proxy-manager/nginx-proxy-manager
sudo docker compose up -d
坑 4:系统盘旧 Docker 数据未自动清理
现象: 切换完成后 df -h / 显示系统盘占用没有变化,还是 11G。
原因: /var/lib/docker 旧目录不会自动删除,需要手动清理。
处理方式: 确认所有应用正常运行后再删除:
# 确认 Docker 路径已切换
sudo docker info | grep "Docker Root Dir"
# 确认应用全部正常
sudo docker ps --format "table {{.Names}}\t{{.Status}}"
# 确认无误后删除旧数据
sudo rm -rf /var/lib/docker
# 清理悬空镜像
sudo docker image prune -f
坑 5:iptv-spider 等通过 yml 手动创建的容器报 warning,同样是镜像丢失导致的问题,拉取镜像即可在容器的编排界面启动
现象:
the attribute `version` is obsolete, it will be ignored
原因: Docker Compose v2 已废弃 version 字段,这只是一个警告,不影响容器启动,可以忽略或删除 compose 文件里的 version: '3' 那行。
四、最终结果
迁移前:
系统盘:28G 总量,已用 11G,使用率 41%
Docker Root Dir: /var/lib/docker(系统盘)
迁移后:
系统盘:28G 总量,已用 6.3G,使用率 25%(释放约 5G)
Docker Root Dir: /vol1/docker(数据盘)
/vol1:120G 总量,已用 12G,使用率 10%
所有应用恢复正常运行:frpc、NPM、Halo、PostgreSQL、MCSManager(daemon+web)、pgAdmin4、Hermes-Agent、iptv-spider。
五、注意事项与后续维护
⚠️ 重要:升级后检查 data-root 是否被重置
1Panel 升级或飞牛 OS 系统升级后,daemon.json 有可能被覆盖,导致 data-root 回退到默认的 /var/lib/docker。
每次升级后必须执行一次检查:
sudo docker info | grep "Docker Root Dir"
如果显示 /var/lib/docker 而不是 /vol1/docker,说明被重置了,重新修改 daemon.json 并重启 Docker:
# 在 daemon.json 里重新加入 data-root
sudo vim /etc/docker/daemon.json
# 加入:"data-root": "/vol1/docker"
sudo systemctl restart docker
sudo 1pctl restart
建议备份一份配置:
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.backup
定期清理 Docker 无用资源
# 清理悬空镜像(无标签、无容器引用的镜像层)
sudo docker image prune -f
# 更激进:清理所有未使用的镜像、容器、网络、缓存
sudo docker system prune -f
监控系统盘使用率
# 快速查看关键分区
df -h / /vol1 /vol2
六、FAQ
Q:重建应用会丢数据吗?
A:不会。重建只是重新创建容器(docker rm + docker run),数据卷是 bind mount 到宿主机目录的,容器删了数据还在原地,重建后重新挂载回来,完整无损。
Q:飞牛 OS 自带的 Docker 图形界面和 1Panel 会冲突吗?
A:不会。两者共用同一个 dockerd 进程,只是管理界面不同。修改 daemon.json 后两边都生效,飞牛 OS 的 Docker 面板也会同步显示新路径下的容器和镜像。
Q:为什么不直接把 1Panel 也装到数据盘?
A:可以,重装时加 --base-dir /vol1/1panel 参数即可。但 /opt/1panel/apps 下存的主要是应用配置文件(compose、env 等),体积很小(本案例约 700M),相比镜像的十几 G 影响不大。如果系统盘实在紧张,可以后续再做这一步。
Q:du 显示 overlay2 有 16G 但系统盘只用了 11G,正常吗?
A:正常。overlay2 大量使用硬链接,多个镜像层共享同一文件,du 会重复计算每个硬链接,导致数值虚高。实际占用以 df 显示的为准。
七、相关命令速查
# 查看 Docker 数据目录
sudo docker info | grep "Docker Root Dir"
# 查看磁盘占用
df -h /
df -h /vol1
# 停止/启动 1Panel(飞牛 OS 环境)
sudo 1pctl stop
sudo 1pctl start
sudo 1pctl status
# 停止/启动 Docker
sudo systemctl stop docker.socket && sudo systemctl stop docker
sudo systemctl start docker
# 查看所有容器状态
sudo docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# 手动启动应用(绕过 1Panel 重建)
cd /opt/1panel/apps/<应用名>/<应用名>/
sudo docker compose up -d
# 查看容器日志
sudo docker logs <容器名> --tail 50
# 清理无用镜像
sudo docker image prune -f