1. 问题现象与背景分析
最近在帮客户做Docker环境迁移时遇到一个棘手问题:明明已经完成了Docker到containerd的迁移,但系统盘空间依然持续告急。通过df -h查看,/var/lib/docker目录确实已经清空,但磁盘使用率仍然高达95%以上。这种情况在Kubernetes 1.24+版本迁移过程中尤为常见,因为该版本开始不再内置Dockershim支持。
经过深入排查,发现罪魁祸首是containerd的存储管理机制。虽然Docker已被卸载,但containerd默认会继续使用/var/lib/containerd目录存储镜像和容器数据。更隐蔽的是,旧Docker实例遗留的overlay2挂载点可能仍然占用空间,而常规的ls命令无法直接发现这些"幽灵"存储。
关键提示:Docker和containerd虽然共享部分底层技术,但它们的存储目录是完全独立的。迁移后必须同时检查两个运行时组件的存储占用情况。
2. 存储机制深度解析
2.1 Docker与containerd的存储差异
Docker采用分层存储架构,主要涉及以下目录:
- /var/lib/docker/overlay2:容器读写层(实际占用最大)
- /var/lib/docker/image:镜像元数据
- /var/lib/docker/containers:容器日志和配置
而containerd的存储结构更为精简:
- /var/lib/containerd/io.containerd.content.v1.content:镜像blob数据
- /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs:快照数据(相当于Docker的overlay2)
- /run/containerd:运行时临时文件
迁移过程中常见的存储"黑洞"包括:
- 未清理的Docker日志文件(可能位于/var/log/containers)
- 残留的overlay2挂载点(需通过mount | grep overlay检查)
- containerd的陈旧快照(默认不会自动清理)
2.2 磁盘空间追踪实战
推荐使用以下命令组合进行精确诊断:
bash复制# 查看各目录大小
du -h --max-depth=1 /var/lib | sort -h
# 检查隐藏的挂载点
mount | grep overlay | grep -v kubelet
# 分析containerd空间占用
sudo ctr content ls -q | xargs sudo ctr content info | grep Size
我曾遇到一个典型案例:某生产环境迁移后,发现/run/containerd目录占用了20GB空间。原因是containerd的临时文件未正确清理,通过重启containerd服务并执行定期维护脚本解决了问题。
3. 彻底清理方案
3.1 安全清理Docker残留
在确认containerd运行正常后,执行以下清理步骤:
bash复制# 1. 卸载Docker组件
sudo apt-get purge docker-ce docker-ce-cli containerd.io
# 2. 手动删除残留目录(危险操作!务必先确认)
sudo rm -rf /var/lib/docker/*
sudo rm -rf /etc/docker
# 3. 清理关联挂载点
for mount in $(mount | grep overlay | awk '{print $3}'); do
sudo umount $mount
done
重要警告:直接删除/var/lib/docker可能导致数据不可恢复!建议先备份重要容器数据。
3.2 优化containerd存储
containerd默认采用异步垃圾回收机制,需要手动触发清理:
bash复制# 查看当前磁盘使用
sudo ctr namespaces list
sudo ctr -n k8s.io images list
# 执行垃圾回收
sudo ctr -n k8s.io images prune -a
sudo ctr -n k8s.io content prune
对于生产环境,建议在/etc/containerd/config.toml中添加自动清理配置:
toml复制[plugins."io.containerd.gc.v1.scheduler"]
deletion_threshold = 10
mutation_threshold = 100
schedule_delay = "10m"
startup_delay = "5m"
4. 长效预防措施
4.1 存储监控方案
建议部署以下监控项:
- 节点磁盘使用率(建议阈值:85%)
- containerd存储目录增长趋势
- 容器日志轮转状态
Prometheus示例配置:
yaml复制- job_name: 'node_disk'
static_configs:
- targets: ['node-exporter:9100']
metrics_path: '/metrics'
params:
collect[]: ['diskstats','filesystem']
4.2 自动化清理脚本
创建定期执行的维护脚本(如/usr/local/bin/containerd-cleanup):
bash复制#!/bin/bash
# 清理超过30天的旧镜像
sudo ctr -n k8s.io images prune --all --expire 720h
# 清理孤立的数据块
sudo ctr -n k8s.io content prune
# 清理临时文件
find /run/containerd -type f -mtime +7 -delete
通过systemd timer每周执行:
ini复制# /etc/systemd/system/containerd-cleanup.timer
[Unit]
Description=Weekly containerd cleanup
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=timers.target
5. 疑难问题排查
5.1 常见报错处理
问题1:执行ctr命令时报"connection refused"
bash复制sudo systemctl restart containerd
sudo ln -s /run/containerd/containerd.sock /var/run/
问题2:磁盘空间释放后仍显示占用
bash复制# 可能是文件已被删除但进程仍持有句柄
sudo lsof +L1 | grep deleted
sudo systemctl restart containerd docker(如果存在)
5.2 高级诊断工具
-
btrfs:如果使用btrfs文件系统,需要特殊处理
bash复制sudo btrfs filesystem df /var/lib/containerd sudo btrfs balance start -dusage=90 /var/lib/containerd -
bcc-tools:追踪文件系统操作
bash复制sudo opensnoop-bpfcc | grep containerd sudo ext4slower-bpfcc /var/lib/containerd -
fstrim:对SSD设备优化
bash复制sudo fstrim -v /var/lib/containerd
在最近一次金融行业客户迁移中,通过组合使用上述工具,发现是某个DevOps工具持续生成临时镜像导致空间泄漏。最终通过调整CI/CD流水线配置解决了问题。
