Containerd快照层残留问题
概述
在现代容器化环境中,Docker 引擎逐渐将其底层存储管理迁移至 containerd。当启用 containerd-snapshotter 特性后,镜像层的存储由 containerd 的快照组件管理。然而,一个已知的问题是:中断的镜像拉取(pull)操作会永久性地占用磁盘空间,且无法通过 docker system prune 等标准命令清除。这为 SRE 的日常运维(如磁盘空间监控与回收)带来了额外挑战,可能引发因磁盘空间耗尽导致的生产事故。理解此问题的根源和解决方案,对于保障主机的可靠性和存储健康至关重要。
核心概念
- Containerd Snapshotter: containerd 中的一个插件,负责管理容器运行所需的文件系统快照。当 Docker 配置使用此功能时,
docker pull的层提取操作由快照器处理,数据存储在 containerd 的目录结构中。 - Overlayfs 快照 (
io.containerd.snapshotter.v1.overlayfs): 这是快照器的一种具体实现,用于存储解压后的镜像层。中断的拉取操作会留下未完成或孤立的快照数据。 - 内容寻址存储 (
io.containerd.content.v1.content): 存储从仓库下载的原始镜像层包(通常是压缩的 tar 文件)。即使快照被清理,这些内容也可能因引用关系而残留。 - 垃圾回收 (Garbage Collection, GC): containerd 用于清理未引用对象的机制。它通常由 Docker daemon 或 containerd 自身定期运行,但可能存在策略限制,无法清理特定状态的残留数据。
- 租约 (Lease): containerd 用于追踪一组相关对象(如一次拉取操作涉及的所有内容和快照)生命周期的机制。中断的操作可能产生一个未被正确释放的租约,从而阻止 GC 回收其关联的数据。
实践
1. 诊断问题
首先确认问题是否存在。中断一次拉取后,使用以下命令检查磁盘占用:
# 查看Docker报告的磁盘使用,注意Images部分
docker system df -v
# 直接查看containerd存储目录的磁盘使用
du -sh /var/lib/docker/io.containerd.snapshotter.v1.overlayfs
du -sh /var/lib/docker/io.containerd.content.v1.content
如果这些目录持续增大,且docker system prune -a无法释放其空间,则问题存在。
2. 检查与清理孤立租约
使用 containerd 的命令行工具 ctr 检查未完成的租约。这是释放关联数据的关键。
# 列出所有租约
sudo ctr -n moby leases ls
# 查找可能由中断拉取创建的、状态异常的租约(通常没有标签或关联引用)
# 删除可疑的租约(请谨慎操作,确认其不属于正常运行)
sudo ctr -n moby leases rm <lease-id>
删除租约后,containerd 的垃圾回收可能在下次运行时回收关联的数据。
3. 强制清理与手动干预
如果上述方法无效,可能需要停止 Docker 服务后手动清理,但这会导致所有容器停止,应在维护窗口进行:
# 停止Docker服务
sudo systemctl stop docker
# 谨慎删除残留的快照和内容目录(路径需根据实际环境确认)
sudo rm -rf /var/lib/docker/io.containerd.snapshotter.v1.overlayfs/???
sudo rm -rf /var/lib/docker/io.containerd.content.v1.content/blobs/sha256/???
# 重启Docker服务
sudo systemctl start docker
注意: 手动删除是最后的手段,务必确保不误删正在使用的快照。最佳实践是在删除前进行备份或仔细核对目录内容。
SRE 要点
- 与可靠性的关联:此问题直接威胁主机的存储可靠性。未释放的磁盘空间可能导致关键服务(如数据库、应用容器)因写入失败而崩溃,属于潜在的单点故障。SRE 需将此类存储泄漏纳入容量规划和告警监控。
- 可观测性缺口:标准的 Docker 监控工具(
docker system df)无法准确反映 containerd 快照器管理的真实磁盘使用情况,造成了可观测性的盲区。SRE 需要建立对/var/lib/docker/下特定目录的监控,并设置磁盘空间使用率告警。 - 事件响应与最佳实践:
- 最佳实践:在生产环境中,对于启用
containerd-snapshotter的节点,应建立定期(如每日)检查租约并清理异常租约的运维脚本。将其纳入自动化运维流程。 - 反模式:忽视
docker system df与实际du值之间的持续差异;在没有确认安全的情况下直接执行rm -rf。 - 操作流程:当收到磁盘空间告警时,应优先使用
du结合ctr leases进行诊断,优先尝试通过清理租约让 GC 生效,而非直接手动删除文件。
- 最佳实践:在生产环境中,对于启用
- 相关指标 (SLI/SLO):
- SLI (Service Level Indicator):可以定义“容器主机可用磁盘空间百分比”作为存储可靠性的 SLI。
- SLO (Service Level Objective):为该 SLI 设置目标,例如“在 99.9% 的时间里,Docker 根目录 (
/var/lib/docker) 的可用空间大于 15%”。 - 通过监控此 SLI,可以提前发现因存储泄漏导致的容量问题,并触发相应的运维操作(如执行上述清理流程),从而避免违反 SLO。
docker-storage-cleanup containerd-garbage-collection disk-capacity-planning