如果你想删除一个标签而不是一个镜像清单,这比表面上看起来要复杂一些。首先,你的注册表需要允许删除镜像,这在 registry:2
镜像中默认未开启。简单的方法是在容器上设置环境变量 REGISTRY_STORAGE_DELETE_ENABLED=true
。
接下来,要意识到标签和镜像清单之间的区别。镜像清单由摘要表示,是指向图像配置和层的JSON数据。标签指向清单,但多个标签可能指向同一清单,而一个清单可能没有任何标签指向它。如果你删除一个清单,那也会删除所有指向该清单的标签,所以在删除标签时要小心,以免意外删除你想保留的标签所引用的清单。
因此,普通的做法存在问题。普通的做法是查询注册表以获取你想要删除的清单的摘要,然后删除该摘要。你可以从标头中获取该摘要。
acceptM="application/vnd.docker.distribution.manifest.v2+json"
acceptML="application/vnd.docker.distribution.manifest.list.v2+json"
curl -H "Accept: ${acceptM}" \
-H "Accept: ${acceptML}" \
-I -s "https://registry.example.org/v2/${repo}/manifests/${tag}"
然后对该摘要发出的删除请求将删除清单以及所有指向它的标签:
curl -H "Accept: ${acceptM}" \
-H "Accept: ${acceptML}" \
-X DELETE -s "https://registry.example.org/v2/${repo}/manifests/${digest}"
然而,如果您只想删除标签,distribution-spec中有一个删除标签的API,但是很少有注册表实现了它。删除的操作如下:
curl -H "Accept: ${acceptM}" \
-H "Accept: ${acceptML}" \
-X DELETE -s "https://registry.example.org/v2/${repo}/manifests/${tag}"
对于不支持此功能的注册表,我找到的最佳解决方案是推送一个替换标签的虚拟证书,然后删除该虚拟证书。使用curl处理这些内容会变得有点繁琐,还有一些媒体类型头部我没有包含进去,而且这并没有提到身份验证。为了应对这些挑战,我转向使用Go语言编写。我自己的工具是regclient,还有类似skopeo和crane的其他工具存在。从regclient中,执行此操作的regctl命令如下:
regctl tag rm registry.example.org/image1:T12
regctl tag rm registry.example.org/image2:T22
regctl tag rm registry.example.org/image5:T22
删除镜像后,你可能希望清理已用的存储空间,并且需要在没有其他推送正在进行时运行垃圾收集(有些会禁用注册表,或者等到知道上传不会运行的时间)。对于registry:2
镜像,GC命令如下:
docker exec registry /bin/registry garbage-collect \
/etc/docker/registry/config.yml --delete-untagged
将删除所有未标记的清单,以及任何未引用的blob。
注意:分发注册表中的未标记清单当前包括多平台镜像的所有子清单。这意味着如果您的注册表中有多平台镜像,则删除未标记的清单可能会导致数据丢失。有一个3178问题来跟踪何时解决此问题。
-H "Accept: ${acceptML}"
-X DELETE -s "https://registry.example.org/v2/${repo}/manifests/${digest}",那么我是否还应该使用命令docker exec registry /bin/registry garbage-collect
/etc/docker/registry/config.yml --delete-untagged来清理未标记的内容? - Fr0zt