Docker镜像仓库的垃圾回收机制深度清理后端存储空间的实现

 更新时间:2026年04月24日 09:24:46   作者:冷漠man  
本文主要介绍了Docker镜像仓库的垃圾回收机制深度清理后端存储空间的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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." >> $LOG

Crontab 配置(每月 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垃圾回收清理后端存储空间内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Docker 安装 LogStash的详细过程

    Docker 安装 LogStash的详细过程

    Logstash,作为Elastic Stack家族中的核心成员之一,是一个功能强大的开源数据收集引擎,在本文中,我们将详细介绍如何借助Docker容器技术快速安装配置Logstash,以实现日志及各类事件数据的无缝集成与实时处理,感兴趣的朋友一起看看吧
    2024-03-03
  • 在Docker容器中部署静态网页的方法教程

    在Docker容器中部署静态网页的方法教程

    这篇文章主要给大家介绍了在Docker容器中部署静态网页的方法教程,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06
  • 在CentOS 7上安装Docker环境的方法与注意事项

    在CentOS 7上安装Docker环境的方法与注意事项

    这篇文章主要介绍了在CentOS 7上安装Docker环境的方法与注意事项,需要的朋友可以参考下
    2016-10-10
  • docker容器启动失败如何查看日志

    docker容器启动失败如何查看日志

    这篇文章主要介绍了docker容器启动失败如何查看日志问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • docker registry删除远程仓库镜像实现方式

    docker registry删除远程仓库镜像实现方式

    文章介绍如何清理Docker Registry中堆积的镜像,通过配置删除功能、启动容器、查看镜像信息并执行删除操作,同时提供基于web-ui的管理方案,优化存储空间使用
    2025-09-09
  • Docker容器Container镜像Image如何存储详解

    Docker容器Container镜像Image如何存储详解

    本文主要介绍Docker容器(Container)和镜像(Image)是如何进行数据存储详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Docker-Compose 容器集群的快速编排方法

    Docker-Compose 容器集群的快速编排方法

    Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API, 就可以在其上利用Compose来进行编排管理,这篇文章主要介绍了Docker-Compose 容器集群的快速编排,需要的朋友可以参考下
    2022-07-07
  • docker之更新jar问题

    docker之更新jar问题

    这篇文章主要介绍了docker之更新jar问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 如何给Docker配置官方国内加速镜像

    如何给Docker配置官方国内加速镜像

    在国内访问 Docker 官方的镜像,一直以来速度都慢如蜗牛。为了快速访问 Docker 官方镜像都会配置三方加速器
    2017-06-06
  • Docker启动容器报错:Ports are not available的解决方案

    Docker启动容器报错:Ports are not available的解决方案

    这篇文章主要介绍了Docker启动容器报错:Ports are not available的解决方案,Docker 将容器程序的端口号映射到宿主机的端口号,是一个 NAT 过程,这个过程可能会因为与 Windows NAT 服务冲突而失效,文中有详细的解决方案,需要的朋友可以参考下
    2024-03-03

最新评论