bigywater.tech
Docker · 21

本地 registry:自建仓库、推送与垃圾回收

在自己的机器上起一个镜像仓库很容易,但删镜像为什么不释放磁盘?这篇用 registry:2 实测:共享层只存一份、DELETE 之后磁盘不变、garbage-collect 才真正回收,以及跨仓库推送时层是怎么被复用的。

405 → 202
默认配置下 DELETE manifest 返回 405;开启删除后返回 202
8320 → 6248 KB
garbage-collect 前后 registry 磁盘上的 blob 数据大小(7 → 4 个文件)
2 行 Mounted from
同一个镜像推到另一个仓库名时,层直接从原仓库挂载

默认不能删

实测 · 本机执行输出
  DELETE /v2/c16/app/manifests/<digest> → 405;正文:{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}

registry:2 默认拒绝删除:DELETE manifest 返回 405 UNSUPPORTED。需要在启动时设置环境变量 REGISTRY_STORAGE_DELETE_ENABLED=true。

共享层只存一份

实测 · 本机执行输出
  推 app:1 后:registry 磁盘上 blob 文件 4 个,共 6216 KB
  再推 app:2 后:blob 文件 7 个,共 8352 KB(新增 3 个文件、2136 KB;输出里 "Layer already exists" 1 行)

两个镜像共用 alpine 基础层,各自有一个 2 MiB 的随机文件。推完两个镜像,磁盘上只有 7 个 blob 文件(8352 KB),第二次推送输出里有一行 Layer already exists。

DELETE 不等于释放磁盘

实测 · 本机执行输出
  DELETE manifests/<app:1 的 digest> → 202
  tags/list → {"name":"c16/app","tags":["2"]}
  GET manifests/1 → 404
  删除后磁盘上 blob 文件 7 个,共 8320 KB(删除前 7 个、8352 KB)

删除 app:1 的 manifest 后,tag 消失、GET 返回 404,但磁盘占用从 8352 KB 只降到 8320 KB。层的数据文件都还在。

garbage-collect

实测 · 本机执行输出
  --dry-run:退出码 0;输出里 "eligible for deletion" 的行数 4
  dry-run 之后磁盘:7 个 blob 文件、8320 KB
  真正执行:退出码 0;输出里 "eligible for deletion" 的行数 4
  GC 之后磁盘:4 个 blob 文件、6248 KB(回收了 3 个文件、2072 KB)

在 registry 容器里执行 registry garbage-collect /etc/docker/registry/config.yml 才会回收没人引用的 blob:磁盘从 8320 KB 降到 6248 KB,7 个文件变 4 个。先用 --dry-run 看一遍不会改动。回收时有新的写入会怎样,我没有测。

不影响其它镜像

实测 · 本机执行输出
  docker pull app:2 → 退出码 0;localhost:9701/c16/app:2
  docker pull app:1(已删除)→ 退出码 1;Error response from daemon: failed to resolve reference "localhost:9701/c16/app:1": localhost:9701/c16/app:1: not found

回收之后,没被删除的 app:2 可以重新拉取;已删除的 app:1 报 not found。

跨仓库挂载

实测 · 本机执行输出
  push 退出码 0;输出里 "Mounted from" 的行数 2,"Layer already exists" 的行数 0
  f0deb84d7ced: Mounted from c16/app | 3f26bc2dec0b: Mounted from c16/app
  之后磁盘:4 个 blob 文件、6336 KB(推之前 4 个、6248 KB)

同一个 registry 里,把 c16/app:2 推成 c16/other:2,docker 输出 Mounted from c16/app,没有重新上传层内容。磁盘上的 blob 文件数不变,总大小多了 88 KB(我没有查那是什么,推测是新仓库的元数据)。

分步演示

本地 registry
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。registry:2 经 dpull.py 加载,运行在本机 127.0.0.1 的 9700、9701 端口上(一个默认配置、一个开启删除);磁盘用量用容器内 du -sk /var/lib/registry 和 find 统计 blob 数据文件;2 MiB 文件是 os.urandom 随机数据(层几乎不可压缩);实验后已删除容器和镜像
    • 没有验证:Docker Hub 或 Harbor 等其它实现的删除与回收、使用外部存储(S3、本地卷)时的行为、回收与并发推送的冲突、认证与 HTTPS、镜像带 provenance 证明时 DELETE 的影响、registry 的缓存(pull-through)模式
    京ICP备2026067502号-1京公网安备11010502063487号