上周五晚上我正在撸代码,突然收到疯狂报警,服务器 / 分区使用率 92%!”。
登录服务器一看,根目录确实快满了,但 /data(挂载在 vdb 上)还有大把空闲。但是我早就把 Docker 的 data-root 迁到 vdb 上了,怎么系统盘还是被撑爆了?
df -h 看了一眼,overlay 挂载点确实显示在 vdb 上,空间还很充裕。但 du -sh / 一查,根目录下 /var/lib/containerd 赫然占了 24GB!
overlay挂载目录和实际存储目录不在同一个地方,这什么情况,之前的服务器都没有出现过这个情况。
一、问题检查
# 明明设了 data-root 到 /data/docker
$ docker info | grep "Docker Root Dir"
Docker Root Dir: /data/docker
# df 看 overlay 也是 vdb 设备
$ df -h | grep overlay
overlay 100G 20G 80G 20% /var/lib/docker/overlay2/xxx/merged
# 但根分区还是被吃光
$ df -h /
/dev/vda1 50G 46G 4G 92% /
二、排查过程:初步估计是版本的问题
第一步:确认 Docker 到底把数据写哪了
docker info 给的 Docker Root Dir 是 /data/docker,没错。我又去 /data/docker 下 du -sh 一看,只有 2.4GB。那剩下的 40 多 GB 去哪了?
第二步:发现“真凶”
顺着 /var/lib 往下翻,/var/lib/containerd 竟然有 24GB。再仔细看,里面有个 io.containerd.snapshotter.v1.overlayfs 目录,全是镜像层数据。
按这个关键字去查找,确实发现了原因,新版本的docker的存储,换地方了,甚至不是用同一个存储方式了。
本质原因
新版的docker的底层也逐渐迁移到container上了。
三、解决方案:让 Containerd 也“搬家”
既然问题根源是 containerd 的 root 目录还在系统盘,那就把它也迁到数据盘(vdb)上。
方案选择:mv 还是 rsync?
我测试了下,跨盘移动大文件夹,mv 和 rsync 的本质都是“复制+删除”。但 rsync 支持断点续传和进度显示,尤其在生产环境,我强烈推荐用 rsync,虽然稍慢一点,但安心。
操作步骤
1. 停止一切容器和服务
docker stop $(docker ps -aq)
systemctl stop docker containerd
重要! 必须停 containerd,否则文件被占用,迁移会失败。
2. 创建新目录并同步数据
mkdir -p /data/containerd
rsync -avP --remove-source-files /var/lib/containerd/ /data/containerd/
--remove-source-files 是传完一个删一个,类似 mv 的效果,但更安全。
3. 修改 containerd 配置
新建配置文件:
touch /etc/containerd/config.toml
写入
root = "/data/containerd"
4. 启动服务并验证
systemctl start containerd docker
检查是否生效:
ps aux | grep containerd | grep root
# 应该看到 --root /data/containerd
确认所有容器正常,然后删除旧目录备份,检查磁盘释放成功,
rm -rf /var/lib/containerd
df -ah
四、深入原理:为什么 Docker 要搞这么复杂?
很多朋友可能还停留在“Docker 所有东西都在 /var/lib/docker”的印象里。其实从 Docker 1.11(2016 年) 开始,Docker 就把底层容器运行时抽离成了 containerd,并独立管理镜像快照。
更“刺激”的是,从 Docker 29 版本开始,镜像存储彻底移入 containerd,/var/lib/docker 只剩元数据了。但升级不会自动迁移,所以如果你从 27 升到 29,老数据还在老地方,新镜像才进新目录,会造成更混乱的局面。
这就好比公司搬家,老员工还坐老工位,新员工去新工位,行政不管,乱成一锅粥。
因此,无论你用的是哪个 Docker 版本,只要发现系统盘空间异常,第一件事就是检查 /var/lib/containerd 的大小。
五、总结 + 避坑指南
| 检查点 | 命令 | 预期 |
|---|---|---|
| Docker 根目录 | docker info | grep "Docker Root Dir" |
应在数据盘 |
| Containerd 根目录 | ps aux | grep containerd | grep root |
应在数据盘 |
| 磁盘占用分布 | du -sh /var/lib/containerd /var/lib/docker |
两者都在数据盘 |
| 升级后存储驱动 | docker info | grep "Storage Driver" |
若为 overlay2 则还是旧模式,如需新模式需手动启用 features.containerd-snapshotter |
新装服务器时,第一步就把 Docker 和 Containerd 的根目录都配置到数据盘。
