我运行一个私有的Docker仓库,我希望从一个仓库中删除除latest
以外的所有镜像。我不想删除整个仓库,只想删除其中的一些镜像。 API文档没有提到这种方法,但肯定是可以实现的吧?
我运行一个私有的Docker仓库,我希望从一个仓库中删除除latest
以外的所有镜像。我不想删除整个仓库,只想删除其中的一些镜像。 API文档没有提到这种方法,但肯定是可以实现的吧?
目前您无法使用注册表 API来完成这个任务。它只允许您删除仓库或特定标签。
通常情况下,删除一个仓库意味着与该仓库关联的所有标签都将被删除。
删除标签意味着删除图像和标签之间的关联。
上述任何操作都不会删除单个图像。它们仍然保存在您的磁盘上。
此解决方法需要您将 Docker 镜像存储在本地。
您可以通过删除除最新标签以外的所有标签来实现解决方案的变通方法,并可能因此删除与其相关联的图像引用。然后,您可以运行此脚本来删除未被任何标签引用或任何已使用图像的祖先引用的所有图像。
考虑一个图像图形,其中大写字母(A
、B
等)表示短的图像 ID,<-
表示一个图像基于另一个图像:
A <- B <- C <- D
现在我们给图片添加标签:
A <- B <- C <- D
| |
| <version2>
<version1>
在这里,标签<version1>
引用了图像C
,而标签<version2>
引用了图像D
。
在您的问题中,您说您想要删除除“latest
”之外的所有图像。现在,这个术语并不完全正确。您混淆了图像和标签。从图表上看,我认为您会同意标签<version2>
代表最新版本。实际上,根据这个问题的说法,您可以拥有一个表示最新版本的标签:
A <- B <- C <- D
| |
| <version2>
| <latest>
<version1>
由于<latest>
标签引用了图像D
,我要问您:您真的想删除除图像D
之外的所有内容吗?可能不是!
如果您使用Docker REST API删除<version1>
标签,则会获得以下结果:
A <- B <- C <- D
|
<version2>
<latest>
注意: Docker 永远不会删除镜像!即使它这样做了,在这种情况下也无法删除镜像,因为镜像 C
是标记为 D
的祖先的一部分。
即使使用了 此脚本 ,也不会删除任何镜像。
在你能够控制其他人何时从你的注册表中提取或推入镜像的情况下(例如通过禁用 REST 接口),如果没有其他镜像基于它并且没有标签引用它,则可以从镜像图中删除镜像。
请注意,在以下图表中,镜像 D
不是基于 C
而是基于 B
。 因此,D
不依赖于 C
。 如果您在此图表中删除标记 <version1>
,则镜像 C
将不被任何镜像使用,此时此脚本 可以删除它。
A <- B <--------- D
\ |
\ <version2>
\ <latest>
\ <- C
|
<version1>
清理后,您的图像图表如下所示:
A <- B <- D
|
<version2>
<latest>
这是你想要的吗?
REGISTRY_STORAGE_DELETE_ENABLED=true
来实现。$ curl -sS <domain-on-ip>:5000/v2/_catalog
{
"repositories": [
<repo>,
...
]
}
$ curl -sS <domain-on-ip>:5000/v2/<repo>/tags/list
{
"name": <repo>,
"tags": [
<tag>,
...
]
}
$ curl -sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \
-o /dev/null \
-w '%header{Docker-Content-Digest}' \
<domain-or-ip>:5000/v2/<repo>/manifests/<tag>
Accept
头。如果没有它,你将得到一个不同的值,删除操作将失败。-w
选项仅在CURL v7.83.0及以上版本中支持。在较旧的CURL版本中,您需要使用其他工具(如sed、grep或awk)从输出中提取头内容。sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073
$ curl -sS -X DELETE <domain-or-ip>:5000/v2/<repo>/manifests/<digest>
在您的Docker注册表容器中运行以下命令:
$ registry garbage-collect /etc/docker/registry/config.yml
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
删除 blob: /docker/...
”的消息,但它并没有改变磁盘空间的使用。使用 _bin/registry github.com/docker/distribution v2.4.1_。 - JamesThomasMoonAccept: application/vnd.docker.distribution.manifest.v2+json
头部信息,一直收到 MANIFEST_UNKNOWN
错误。尽管在他们的文档(https://docs.docker.com/registry/spec/api/)中有提到,但仍然很令人困惑。 - Tomasz Wv2
仓库支持通过DELETE /v2/<name>/manifests/<reference>
进行删除操作。GET /v2/<name>/manifests/<tag>
请求的Docker-Content-Digest
头获取<reference>
(请注意,此请求需要Accept:application/vnd.docker.distribution.manifest.v2+json
头)。REGISTRY_STORAGE_DELETE_ENABLED=true
)。{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
。 - Gadelkareem{"errors":[{"code":"UNSUPPORTED","message":"操作不支持。"}]}
有任何建议吗? - Kumaresan P这真的很丑,但它有效。文本已在registry:2.5.1上进行测试。 即使更新配置以启用删除,我仍然无法使删除平稳运行。获取ID非常困难,必须登录才能获得,可能存在一些误解。无论如何,以下方法有效:
进入容器
docker exec -it registry sh
定义变量以匹配您的容器和容器版本:
export NAME="google/cadvisor"
export VERSION="v0.24.1"
进入注册表目录:
cd /var/lib/registry/docker/registry/v2
删除与您的哈希相关的文件:
find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
删除清单:
rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
退出登录
exit
运行垃圾回收器:
docker exec -it registry bin/registry garbage-collect /etc/docker/registry/config.yml
如果所有操作都正确执行,将会显示关于删除的Blobs的一些信息。
问题1
您提到这是您的私有Docker注册表,因此您可能需要检查Registry API而不是您提供的Hub registry API doc链接。
问题2
Docker注册表API是客户端/服务器协议,由服务器的实现决定是否删除后端中的映像。(我猜)
DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)
详细解释
根据您的描述,我将演示它是如何工作的。
我运行一个私有的Docker仓库。
我使用默认设置,并监听端口5000
。
docker run -d -p 5000:5000 registry
$ docker tag ubuntu localhost:5000/ubuntu
$ docker push localhost:5000/ubuntu
The push refers to a repository [localhost:5000/ubuntu] (len: 1)
Sending image list
Pushing repository localhost:5000/ubuntu (1 tags)
511136ea3c5a: Image successfully pushed
d7ac5e4f1812: Image successfully pushed
2f4b4d6a4a06: Image successfully pushed
83ff768040a0: Image successfully pushed
6c37f792ddac: Image successfully pushed
e54ca5efa2e9: Image successfully pushed
Pushing tag for rev [e54ca5efa2e9] on {http://localhost:5000/v1/repositories/ubuntu/tags/latest}
之后我可以使用注册表 API来检查它是否存在于您的私有 Docker 注册表中。
$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags
{"latest": "e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37"}
$ curl -X DELETE localhost:5000/v1/repositories/ubuntu/tags/latest
true
请再检查一遍,该标签在我的私有注册服务器中不存在。
$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}
有一些客户端(如Python、Ruby等)可以做到这一点。但我认为,在我的注册表服务器上安装运行时(例如Python)仅仅是为了维护我的注册表并不可持续!
因此,deckschrubber
是我的解决方案:
go install github.com/fraunhoferfokus/deckschrubber@latest
$GOPATH/bin/deckschrubber
自动删除指定年龄之前的图片。可以使用 -year
、-month
、-day
或它们的组合来指定图片的年龄。
$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000
更新:这里是关于deckschrubber的简短介绍:https://blog.quaintous.com/2017/05/19/docker-registry-housekeeping/
deckschrubber
非常好用 - 安装非常简单(单个二进制文件),可以按名称(使用正则表达式匹配)和年龄删除图像。 - RichVellatest
之外的所有标签变得复杂,因为同一个镜像清单可以被多个标签指向,所以当你删除一个标签的清单时,可能会有效地删除多个标签。registry:2
镜像,这涉及使用环境变量REGISTRY_STORAGE_DELETE_ENABLED=true
(或等效的yaml配置)启动它。#!/bin/sh
repo="localhost:5000/repo/to/prune"
for tag in $(regctl tag ls $repo); do
if [ "$tag" != "latest" ]; then
echo "Deleting: $(regctl image digest --list "${repo}:${tag}") [$tag]"
regctl tag rm "${repo}:${tag}"
fi
done
regctl
命令来自regclient,regctl tag rm
逻辑首先尝试执行最近添加到distribution-spec的标签删除API。由于大多数注册表尚未实现该规范,它会回退到清单删除API,但首先创建一个虚拟清单来覆盖标签,然后删除该新摘要。这样做的话,如果旧的清单被其他标签使用,它不会删除那些其他标签。latest
摘要之外的清单的替代版本脚本如下:#!/bin/sh
repo="localhost:5000/repo/to/prune"
save="$(regctl image digest --list "${repo}:latest")"
for tag in $(regctl tag ls $repo); do
digest="$(regctl image digest --list "${repo}:${tag}")"
if [ "$digest" != "$save" ]; then
echo "Deleting: $digest [$tag]"
regctl manifest rm "${repo}@${digest}"
fi
done
regclient/regbot
,它允许你定义这个策略并让它持续运行以不断修剪你的注册表。
registry:2
图像:docker exec registry /bin/registry garbage-collect \
/etc/docker/registry/config.yml --delete-untagged
注意:垃圾收集工具存在一个已知问题,会删除多平台镜像的未打标签的子清单。如果您正在使用多平台镜像,请确保每个特定平台的镜像都已经打上标签,或者在问题在您部署的版本中得到解决之前避免使用上述GC命令。
我通常支持使用脚本来完成任务,但如果您已经在运行从Joxit/docker-registry-ui构建的注册表UI容器,则最好直接在UI中选择单击删除按钮,并一次删除一页图像,然后进行垃圾回收。
您可以使用的另一个工具是registry-cli。例如,该命令:
registry.py -l "login:password" -r https://your-registry.example.com --delete
将删除除最后10张图像以外的所有图像。
您还可以根据创建日期从代码库中删除一些旧的镜像。
为此,请进入您的Docker注册表容器,并获取某个特定代码库的清单修订列表:
ls -latr /var/lib/registry/docker/registry/v2/repositories/YOUR_REPO/_manifests/revisions/sha256/
curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://DOCKER_REGISTRY_HOST:5000/v2/YOUR_REPO/manifests/sha256:OUTPUT_LINE
bin/registry garbage-collect /etc/docker/registry/config.yml