如何从私人码头注册表中删除图像?

Leo*_*Leo 139 docker docker-registry

我运行一个私有的docker注册表,我想latest从存储库中删除所有图像.我不想删除整个存储库,只删除其中的一些图像.该API文档不提一个办法做到这一点,但肯定这是可能的?

Kon*_*ine 105

目前,您无法使用Registry API执行该任务.它只允许您删除存储库或特定标记.

通常,删除存储库意味着删除与此存储库关联的所有标记.

删除标记意味着删除图像和标记之间的关联.

以上都不会删除单个图像.它们留在磁盘上.


解决方法

对于此变通办法,您需要在本地存储docker镜像.

解决方案的解决方法是删除除最新标记之外的所有标记,从而可能删除对相关图像的引用.然后,您可以运行此脚本以删除任何标记未引用的所有图像或任何使用过的图像的祖先.

术语(图像和标签)

考虑这样的图像图形,其中大写字母(A,, B......)表示短图像ID,并且<-表示图像基于另一图像:

 A <- B <- C <- D
Run Code Online (Sandbox Code Playgroud)

现在我们为图片添加标签:

 A <- B <- C <- D
           |    |
           |    <version2>
           <version1>
Run Code Online (Sandbox Code Playgroud)

这里,标签<version1>引用图像C,标签<version2>引用图像D.

提炼你的问题

在你的问题中,你说你想删除

所有的图像,但 latest

.现在,这个术语不太正确.你混合了图像和标签.查看图表我认为你会同意标签<version2>代表最新版本.事实上,根据这个问题,你可以有一个代表最新版本的标签:

 A <- B <- C <- D
           |    |
           |    <version2>
           |    <latest>
           <version1>
Run Code Online (Sandbox Code Playgroud)

由于<latest>标签引用图像D我问你:你真的想删除除图像以外的所有内容D吗?可能不是!

删除标签会发生什么?

如果您<version1>使用Docker REST API 删除标记,您将得到以下结果:

 A <- B <- C <- D
                |
                <version2>
                <latest>
Run Code Online (Sandbox Code Playgroud)

请记住: Docker永远不会删除图像!即使它这样做,在这种情况下它也不能删除图像,因为图像CD被标记的图像的祖先的一部分.

即使您使用此脚本,也不会删除任何图像.

当图像可以删除

在您可以控制何时可以拉动或推送到您的注册表的情况下(例如,通过禁用REST接口).如果没有其他图像基于图像并且没有标记引用图像,则可以从图像图形中删除图像.

请注意,在下面的图,该图像D没有根据C,但对B.因此,D不依赖于C.如果您删除<version1>此图表中的标记,则C任何图像都不会使用该图像,此脚本可以将其删除.

 A <- B <--------- D
      \            |
       \           <version2>
        \          <latest>
         \ <- C
              |
              <version1>
Run Code Online (Sandbox Code Playgroud)

清理后,您的图像图形如下所示:

 A <- B <- D
           |
           <version2>
           <latest>
Run Code Online (Sandbox Code Playgroud)

这是你想要的吗?

  • 垃圾收集终于到达了注册表v2.4.0 https://docs.docker.com/registry/garbage-collection/ (9认同)
  • 我已经用一种适合我的解决方法编辑了我的答案。我希望它有帮助。 (2认同)

byr*_*edo 57

当前v2注册表现在支持删除viaDELETE /v2/<name>/manifests/<reference>

请参阅:https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image

工作用途:https: //github.com/byrnedo/docker-reg-tool

编辑:<reference>可以从请求中检索上面的清单

GET /v2/<name>/manifests/<tag>

并检查Docker-Content-Digest响应中的标头.

  • 在V2上也得到错误`{"errors":[{"code":"UNSUPPORTED","message":"操作不受支持."}]} (8认同)
  • 此处的其他一些答案显示了如何提取清单引用哈希.这是将标签转换为传递给"DELETE"的东西所必需的. (3认同)

Yav*_*ert 57

我的注册表遇到了同样的问题,然后我从博客页面尝试了下面列出的解决方案.有用.

第1步:列出目录

您可以通过调用此网址列出您的目录:

http://YourPrivateRegistyIP:5000/v2/_catalog
Run Code Online (Sandbox Code Playgroud)

回复将采用以下格式:

{
  "repositories": [
    <name>,
    ...
  ]
}
Run Code Online (Sandbox Code Playgroud)

第2步:列出相关目录的标签

您可以通过调用此网址列出目录的标记:

http://YourPrivateRegistyIP:5000/v2/<name>/tags/list
Run Code Online (Sandbox Code Playgroud)

回复将采用以下格式:

{
"name": <name>,
"tags": [
    <tag>,
    ...
]
Run Code Online (Sandbox Code Playgroud)

}

第3步:列出相关标签的清单值

您可以在docker注册表容器中运行此命令:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'
Run Code Online (Sandbox Code Playgroud)

回复将采用以下格式:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073
Run Code Online (Sandbox Code Playgroud)

使用清单值运行下面给出的命令:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/<name>/manifests/sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073
Run Code Online (Sandbox Code Playgroud)

第4步:删除标记的清单

在docker registy容器中运行此命令:

bin/registry garbage-collect  /etc/docker/registry/config.yml  
Run Code Online (Sandbox Code Playgroud)

这是我的config.yml

root@c695814325f4:/etc# cat /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
Run Code Online (Sandbox Code Playgroud)

  • 我在 /etc/docker/registry/config.yml 文件中将“删除:启用”值设置为 true。对于此配置,无需设置 REGISTRY_STORAGE_DELETE_ENABLED 变量 @AdilIlhan (3认同)
  • 谢谢,这是第一个对我有用的答案。我缺少 `Accept: application/vnd.docker.distribution.manifest.v2+json` 标头并不断收到 `MANIFEST_UNKNOWN` 错误。尽管它位于他们的文档中的某个位置(https://docs.docker.com/registry/spec/api/),但它非常令人困惑。 (3认同)
  • 命令成功,包括有关“删除 blob:/docker/...”的消息,但它没有更改使用的磁盘空间。使用 _bin/registry github.com/docker/distribution v2.4.1_。 (2认同)
  • 要删除映像,应使用REGISTRY_STORAGE_DELETE_ENABLED = true参数运行注册表容器。 (2认同)
  • 步骤 3 不返回任何输出(甚至没有错误!!),任何建议! (2认同)

Lar*_*Cai 15

问题1

您提到它是您的私有docker注册表,因此您可能需要检查Registry API而不是Hub注册表API文档,这是您提供的链接.

问题2

docker注册表API是一个客户端/服务器协议,它取决于服务器是否删除后端中的图像.(我猜)

DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)
Run Code Online (Sandbox Code Playgroud)

详细说明

下面我将根据您的描述演示它的工作原理,作为我对您的问题的理解.

你运行你运行私人docker注册表,我使用默认的一个和侦听5000端口

docker run -d -p 5000:5000 registry
Run Code Online (Sandbox Code Playgroud)

然后我标记本地图像并推入其中.

$ 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}
Run Code Online (Sandbox Code Playgroud)

之后,您可以使用Registry API检查它是否存在于您的私有docker注册表中

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags
{"latest": "e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37"}
Run Code Online (Sandbox Code Playgroud)

现在我可以使用该API删除标签!!

$ curl -X DELETE localhost:5000/v1/repositories/ubuntu/tags/latest
true
Run Code Online (Sandbox Code Playgroud)

再次检查,您的私人注册表服务器中不存在该标记

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}
Run Code Online (Sandbox Code Playgroud)

  • 它从每个注册API服务器的实现来看,从协议的角度来看,它不存在. (3认同)
  • 请参阅下面的答案,了解为什么此命令无效. (2认同)
  • 您删除标签但不删除图像数据.后者是在删除标签后由我引用的脚本完成的.我还使用注册表API删除标记. (2认同)

hir*_*rro 14

这真的很丑,但它有效,文本在注册表上测试:2.5.1.即使在更新配置以启用删除后,我也无法使删除工作顺利进行.该ID真的很难检索,不得不登录才能得到它,也许是一些误解.无论如何,以下工作:

  1. 登录容器

    docker exec -it registry sh
    
    Run Code Online (Sandbox Code Playgroud)
  2. 定义与容器和容器版本匹配的变量:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 移动到注册表目录:

    cd /var/lib/registry/docker/registry/v2
    
    Run Code Online (Sandbox Code Playgroud)
  4. 删除与哈希相关的文件:

    find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
    
    Run Code Online (Sandbox Code Playgroud)
  5. 删除清单:

    rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
    
    Run Code Online (Sandbox Code Playgroud)
  6. 登出

    exit
    
    Run Code Online (Sandbox Code Playgroud)
  7. 运行GC:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
    Run Code Online (Sandbox Code Playgroud)
  8. 如果完成所有操作,则会显示有关已删除blob的一些信息.


Yan*_*oto 8

有一些客户端(在Python,Ruby等)就是这样做的.根据我的口味,在我的注册表服务器上安装运行时(例如Python)是不可持续的,只是为了保持我的注册表!


那么deckschrubber我的解决方案是:

go get github.com/fraunhoferfokus/deckschrubber
$GOPATH/bin/deckschrubber
Run Code Online (Sandbox Code Playgroud)

超过给定年龄的图像会自动删除.年龄可以使用指定的-year,-month,-day,或它们的组合:

$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000
Run Code Online (Sandbox Code Playgroud)

更新:这里是 deckschrubber 的简短介绍.


BMi*_*tch 7

删除除此之外的所有标签的要求latest变得很复杂,因为同一个图像清单可以由多个标签指向,因此当您删除一个标签的清单时,您可能会有效地删除多个标签。

有一些选项可以使其可行。一种是跟踪最新标签的摘要,并仅删除其他摘要的清单,或者您可以使用一些不同的 API 调用来删除标签本身。


无论您如何实现这一点,首先需要将您的注册表配置为允许删除 API。对于最小的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
Run Code Online (Sandbox Code Playgroud)

这里使用的命令regctl来自regclientregctl 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
Run Code Online (Sandbox Code Playgroud)

如果您发现自己需要创建删除策略来自动删除大量图像,我建议您regclient/regbot从同一个存储库中查看,它允许您定义该策略并使其运行以不断修剪您的注册表。


删除映像后,在大多数使用情况下,您需要对注册表进行垃圾收集。例如,registry:2图像如下所示:

docker exec registry /bin/registry garbage-collect \
  /etc/docker/registry/config.yml --delete-untagged
Run Code Online (Sandbox Code Playgroud)

注意:垃圾收集实用程序存在一个未解决的问题,该实用程序将删除多平台映像的未标记子清单。如果您使用多平台映像,则需要确保每个特定于平台的映像都已标记,或者避免使用上述 GC 命令,直到部署版本中的问题得到解决。


归档时间:

查看次数:

206346 次

最近记录:

5 年,11 月 前