Docker镜像仓库的垃圾回收机制深度清理后端存储空间的实现
作者:冷漠man
Docker 镜像仓库的垃圾回收(Garbage Collection, GC)机制是管理后端存储空间的核心手段。其本质是通过标记-清除(Mark and Sweep)算法,识别并删除不再被任何镜像清单(Manifest)引用的 Blob(镜像层和配置对象),从而真正释放磁盘空间。
一、GC 的核心原理:标记-清除两阶段
1. Marking 阶段(标记)
GC 扫描所有仓库(repositories)下的 tags 目录,读取 link 文件获取 manifest 摘要(digest)。随后遍历每个 manifest,提取其中引用的所有 layer 和 config 文件的 digest,将这些 Blob 标记为"存活"(不可删除)。
2. Sweep 阶段(清除)
遍历整个 blobs 目录下的所有 Blob。若某个 Blob 的 digest 不在标记集合中,则将其加入删除集合并执行物理删除。
流程示意:
开始 GC → 扫描所有 Manifest → 标记引用的 Blobs → 遍历所有 Blobs
↓
是否被标记?
是 → 保留 否 → 删除二、为什么必须手动/定时触发 GC?
Docker Registry 的设计遵循内容寻址存储(CAS)原则,多个镜像标签可能共享相同的底层 layer。因此:
- 删除 tag 仅移除引用:当你删除一个镜像标签时,只是删除了 manifest 的引用记录,底层的 blob 文件仍然保留。
- 共享 layer 保护:如果某个 layer 仍被其他镜像引用,GC 不会删除它,避免破坏其他镜像。
- 空间不会自动释放:Registry 不会自动运行 GC,必须手动触发或使用定时任务。
三、执行 GC 的标准操作
前置条件
Registry 配置必须开启删除功能:
storage:
delete:
enabled: true基础 GC 命令
# 进入 Registry 容器执行 docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml # 同时清理未被任何标签引用的 manifest(推荐) docker exec registry bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml # 仅模拟运行,不实际删除(用于验证) docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml
安全实践:只读模式下运行
GC 期间必须禁止写入,否则可能导致数据竞争和损坏:
#!/bin/bash # 将 Registry 切换为只读模式 docker exec registry sh -c 'sed -i "s/readonly: false/readonly: true/" /etc/docker/registry/config.yml && kill -HUP 1' sleep 5 # 执行 GC docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml --delete-untagged # 恢复写入 docker exec registry sh -c 'sed -i "s/readonly: true/readonly: false/" /etc/docker/registry/config.yml && kill -HUP 1'
四、深度清理:处理顽固空间占用
场景 1:手动删除仓库后 GC 效果不佳
如果直接删除了 repositories 目录下的命名空间,但 GC 释放空间很少,原因是:
只要 repositories 目录中的名称空间存在,其下的 blob 文件就不会被回收。
解决方案:
# 1. 先删除 repositories 中的元数据目录 cd /var/lib/registry/docker/registry/v2/repositories && rm -rf <namespace> # 2. 再执行 GC docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
场景 2:清理过期的 Tags 和 Revisions
对于长期运行的 Registry,可以定期清理旧的 tag 和 manifest revision:
# 删除 14 天未更新的 tag 目录
find /var/lib/registry/docker/registry/v2/repositories/*/_manifests/tags/* \
-type d -mtime +14 -maxdepth 1 -exec rm -rf {} \;
# 删除 14 天前的未引用 manifest revision
find /var/lib/registry/docker/registry/v2/repositories/*/_manifests/revisions/sha256/* \
-type d -mtime +14 -maxdepth 1 -exec rm -rf {} \;
# 最后执行 GC
docker exec registry bin/registry garbage-collect -m /etc/docker/registry/config.yml场景 3:清理空目录
GC 后可能残留空目录,占用 inode:
# 删除 blobs/sha256 下的空目录
for dir in $(find /var/lib/registry/docker/registry/v2/blobs/sha256/ -type d -empty); do
rm -rf "$dir"
done五、企业级方案:Harbor 的自动 GC
对于生产环境,建议使用 Harbor 替代原生 Registry。Harbor 提供:
- Web UI 一键删除:删除 tag 后自动标记 manifest
- 定时 GC 任务:在管理界面配置自动垃圾回收计划
- 保留策略:基于镜像年龄、标签模式等自动清理
六、定时自动化脚本示例
#!/bin/bash
# /opt/registry/registry-cleanup.sh
REGISTRY_CONTAINER="registry"
REGISTRY_HOME="/var/lib/registry/docker/registry/v2"
LOG="/var/log/registry-cleanup.log"
echo "[$(date)] Starting cleanup..." >> $LOG
# 1. 清理过期 tags(>30 天)
find ${REGISTRY_HOME}/repositories/*/_manifests/tags/* \
-type d -mtime +30 -maxdepth 1 -exec rm -rf {} \; 2>/dev/null
# 2. 清理过期 revisions
find ${REGISTRY_HOME}/repositories/*/_manifests/revisions/sha256/* \
-type d -mtime +30 -maxdepth 1 -exec rm -rf {} \; 2>/dev/null
# 3. 切换只读模式
docker exec $REGISTRY_CONTAINER sh -c \
'sed -i "s/readonly: false/readonly: true/" /etc/docker/registry/config.yml && kill -HUP 1'
sleep 5
# 4. 执行 GC
docker exec $REGISTRY_CONTAINER bin/registry garbage-collect \
--delete-untagged /etc/docker/registry/config.yml >> $LOG 2>&1
# 5. 恢复写入
docker exec $REGISTRY_CONTAINER sh -c \
'sed -i "s/readonly: true/readonly: false/" /etc/docker/registry/config.yml && kill -HUP 1'
# 6. 清理空目录
find ${REGISTRY_HOME}/blobs/sha256/ -type d -empty -delete 2>/dev/null
echo "[$(date)] Cleanup completed." >> $LOGCrontab 配置(每月 1 日和 15 日凌晨 2:30 执行):
30 2 1,15 * * /opt/registry/registry-cleanup.sh
七、关键注意事项
| 风险点 | 说明 |
|---|---|
| 必须只读运行 | GC 期间任何 push 操作都可能导致数据损坏 |
| 先 dry-run | 首次清理前使用 --dry-run 预览删除内容 |
| 共享 layer 保护 | GC 不会删除仍被引用的 blob,这是正常行为 |
| 大仓库性能 | 超大规模 Registry 的 GC 可能耗时数小时,可考虑增量 GC 方案 |
| 备份优先 | 执行前备份 /var/lib/registry 目录,防止误删 |
通过理解 Registry 的引用计数机制,并结合定期清理 tags、revisions 与 GC 的完整流程,可以有效控制后端存储空间的持续增长。
到此这篇关于Docker镜像仓库的垃圾回收机制深度清理后端存储空间的实现的文章就介绍到这了,更多相关Docker垃圾回收清理后端存储空间内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
