Skip to main content

Command Palette

Search for a command to run...

节省镜像库空间的一个思路

Updated
2 min read

最近遇到一个有趣的状况,某镜像仓库占用了大量的磁盘空间。通常要解决这种问题,给 Registry 发删除指令,并进行 GC 就可以了。然而很多时候,所有镜像都正常,在删除多个 Tag 甚至是 Repository 之后,问题仍然没能缓解,原理也很容易理解——删除的镜像虽然大,可能只是复用了一些比较大的层,删除镜像并不会真正的发出,所以还是需要对镜像库的存储进行更多的了解,进行进一步的统计,在层一级对镜像仓库进行分析,才能获取更有效的途径。

Docker Registry Exporter

首先发现了一个有意思的项目:DockerRegistryExporter,这个项目是一个 Python 编写的 Prometheus Exporter,其中包含四个 Gauge:

-repository_tags_total:按镜像计算的 Tag 数量。 -repository_revisions_total:按镜像计算的版本数量。 -repository_tag_layers_total:以镜像和 Tag 计算的 Layer 数量。 -repository_tag_size_bytes:以镜像和 Tag 计算的文件尺寸。

该镜像使用挂卷的方式,直接对镜像库文件系统进行扫描,例如:

containers:
- image: registry:2
  name: registry
  ports:
  - containerPort: 5000
    name: http
    protocol: TCP
  readinessProbe:
    httpGet:
      path: /
      port: 5000
    initialDelaySeconds: 1
    timeoutSeconds: 1
  livenessProbe:
    httpGet:
      path: /
      port: 5000
    initialDelaySeconds: 1
    timeoutSeconds: 1
  volumeMounts:
  - name: storage
    mountPath: /var/lib/registry

- image: skyuk/docker-registry-exporter:v1.0.0
  name: registry-exporter
  args:
    - /var/lib/registry/docker/registry/v2
  ports:
  - containerPort: 8080
    name: http
    protocol: TCP
  volumeMounts:
  - name: storage
    mountPath: /var/lib/registry

volumes:
- name: storage
  persistentVolumeClaim:
    claimName: registry

通过Sidecar的部署方式和Registry容器共享文件系统,可以定时输出监控指标,例如:

$ curl http://registry:8080
# HELP repository_tag_size_bytes Size of eachtag
# TYPE repository_tag_size_bytes gauge
repository_tag_size_bytes{repository="org/image1", tag="0.3.0"} 162749959.0
repository_tag_size_bytes{repository="org/image2", tag="1009140546"} 226608092.0
...

然而这并不能满足我的要求,关于引用的数据并没有体现,另外前面也提到,我们需要比较精确地获得镜像版本、Tag 和 Layer 之间的引用关系以及各自的尺寸,用 PromQL 有点别扭。

我做了个奇怪的事情

这并不是一个很常见的需求,只能是一个清理之前的准备动作,目前看来我需要找到的就是引用数量少、但是体量比较大的 Layer,但是谁知道以后会需要什么新的标准呢?干脆把这些东西写入到数据库里算了,把这些东西写入数据库之后,还掌握 SQL 这样传统才艺的程序员就可以随便搞一搞其它条件了。

关于镜像仓库的一点基础

镜像库根目录中有两个子目录:blobs 中保存了所有的 Layer,而 repositories 中则是以镜像为单位保存的元数据。

首先看看镜像的数据

$ tree/org/repo/gameserver
.
├── revisions
│   └── sha256
│       └── ecfb0206e8b...
│           └── link
└── tags
    └── latest
        ├── current
        │   └── link
        └── index
            └── sha256
                └── ecfb020...
                    └── link

每个镜像的 Manifests 有两个目录,分别承载的是版本和 Tag,正常来说 Tag 和版本是一致的,但实际上在一些特别情况下,这两个数量可能是不一致的,就会导致只用 Tag 已经无法拉取该镜像,属于一种半孤立状态,应该说是需要清除的。

两个目录中的link文件中包含的是一个哈希码,可以使用这个哈希码在_layers中查找到该镜像的版本/tag 对应的清单层,使用这个字符串可以在根_layer中查到对应的目录,目录下面的data文件中就是每个层的具体数据,对于清单层,其中会是一个json字符串:

{
    "schemaVersion": 2,
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "config": {
        "mediaType": "application/vnd.docker.container.image.v1+json",
        "size": 2694,
        "digest": "sha256:7929bcd70e47d3726d55a870b2ca11c25792758f3ba8b4ff136811f0809af636"
    },
    "layers": [
        {
            "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
            "size": 2546278,
            "digest": "sha256:3db1cceb1cccb362634e914bfe76d329c64d148262a9e139a046337d82e1aeec"
        },
        {
            "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
            "size": 32,
            "digest": "sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1"
        }
    ]
}

这里看到清单中包含两个主节点,configlayer,至此,一个镜像是由三种不同的层构成的:清单、Config 和 Layer。我们关注的主要是 Layer,其中的 data 文件包含的就是各层的具体内容,清单和 Config 中都是文本,Layer 通常都是二进制的,也是我们要关注的主要内容。

接下来的问题就顺理成章了,把 Repository、Tag、Revision 以及 Layer 的关系建立起来,随便用个 SQL 语句,就能够按照具体需求对“引用少、尺寸大”的 Layer 进行过滤了。

相关链接

  • Docker Registry Exporterhttps://github.com/sky-uk/docker-registry-exporter

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts