プライベートDockerレジストリから画像を削除する方法


162

プライベートDockerレジストリを実行していますが、以外のすべてのイメージをlatestリポジトリから削除します。リポジトリ全体を削除するのではなく、リポジトリ内のいくつかの画像を削除します。APIドキュメントは、これを行う方法については言及しませんが、確かにそれは可能ですか?


1
受け入れられた答えはもはや正しくありません(確かに非常に良いですが)。DELETE / v2 / <name> / manifests / <reference>を使用して画像を削除できます:docs.docker.com/registry/spec/api/#deleting-an-image
Michael Zelensky

回答:


116

現在、そのタスクにレジストリAPIを使用することはできません。リポジトリまたは特定のタグのみを削除できます。

一般に、リポジトリを削除すると、このリポジトリに関連付けられているすべてのタグが削除されます。

タグを削除するとは、画像とタグの関連付けが削除されることを意味します。

上記のいずれも単一の画像を削除しません。それらはディスク上に残されます。


回避策

この回避策では、Dockerイメージをローカルに保存する必要があります。

ソリューションの回避策は、最新のタグを除くすべてを削除することで、関連する画像への参照を削除することです。次に、このスクリプトを実行して、タグや参照されたイメージの祖先から参照されていないすべてのイメージを削除できます。

用語(画像とタグ)

大文字は、(このような画像のグラフを検討しAB、...)短い画像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ますか?おそらくない!

タグを削除するとどうなりますか?

<version1>Docker REST APIを使用してタグを削除すると、次のようになります。

 A <- B <- C <- D
                |
                <version2>
                <latest>

注意: Dockerがイメージを削除することはありません!たとえそうであっても、このC画像Dはタグ付けされた画像の祖先の一部であるため、画像を削除することはできません。

このスクリプトを使用しても、画像は削除されません。

画像を削除できる場合

誰かがレジストリをプルまたはプッシュできるタイミングを制御できる状況(たとえば、RESTインターフェースを無効にすることで)。他に基づいている画像がなく、タグがその画像を参照していない場合、画像を画像グラフから削除できます。

次のグラフでは、画像Dはに基づいていないことに注意してください。したがって、に依存しません。このグラフでタグを削除すると、その画像はどの画像でも使用されなくなり、このスクリプトで削除できます。CBDC<version1>C

 A <- B <--------- D
      \            |
       \           <version2>
        \          <latest>
         \ <- C
              |
              <version1>

クリーンアップ後の画像グラフは次のようになります。

 A <- B <- D
           |
           <version2>
           <latest>

これは、あなたの望むことですか?


そのとおりです。タグを削除しても、実際には関連する画像は削除されませんでした。ボックスへのsshアクセスを与えられた画像を削除する方法はありますか?
レオ

1
私は私のために仕事をする回避策で私の答えを編集しました。お役に立てば幸いです。
Konrad Kleine 2014

それはまさにそれです-私はイメージが段階的に構築されることを理解していますが、それらの死んだ枝を枝刈りする方法が必要です。ありがとう!
レオ、

@KonradKleineレジストリから取得した画像のリストから画像グラフをどのように作成しますか?
Rafael Barros

9
ガベージコレクションがレジストリv2.4.0にようやく到着しましたdocs.docker.com/registry/garbage-collection
Markus Lindberg

68

レジストリで同じ問題に直面した後、ブログページから以下の解決策を試しました。できます。

ステップ1:カタログのリスト

次のURLを呼び出すことにより、カタログを一覧表示できます。

http://YourPrivateRegistyIP:5000/v2/_catalog

応答は次の形式になります。

{
  "repositories": [
    <name>,
    ...
  ]
}

ステップ2:関連カタログのタグをリストする

次のURLを呼び出すことにより、カタログのタグをリストできます。

http://YourPrivateRegistyIP:5000/v2/<name>/tags/list

応答は次の形式になります。

{
"name": <name>,
"tags": [
    <tag>,
    ...
]

}

ステップ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)}'

応答は次の形式になります。

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

以下のコマンドをマニフェスト値で実行します。

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

ステップ4:マークされたマニフェストを削除する

docker registyコンテナーで次のコマンドを実行します。

bin/registry garbage-collect  /etc/docker/registry/config.yml  

これが私の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

Deleteing blob: /docker/...」に関するメッセージを含め、コマンドは成功しましたが、使用されたディスク容量は変更されませんでした。bin / registry github.com/docker/distribution v2.4.1を使用します
JamesThomasMoon1979

3
イメージを削除するには、REGISTRY_STORAGE_DELETE_ENABLED = trueパラメーターを指定してレジストリコンテナーを実行する必要があります。
Adil 2017年

3
/etc/docker/registry/config.ymlファイルで "delete:enabled"値をtrueに設定しました。この構成では、REGISTRY_STORAGE_DELETE_ENABLED変数@AdilIlhanを設定する必要はありません
Yavuz Sert

re:ステップ3、「Docker-Content-Digest」はヘッダーにある必要がありますか?(curl出力には表示されません)。マークしたマニフェストを削除する前に、マニフェストをマークした結果を確認して、正常にマークしたことを確認できますか?何を送信しても202応答が返されるようです。
SteveW '19年

Docker-Content-Digest一部には、すなわち、小文字(ドッカエンジンv18.09.2でテスト)にする必要があります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)}'
ムハンマドアブドゥルラフマン

63

現在のv2レジストリは現在、削除をサポートしていますDELETE /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レスポンスのヘッダーを確認します。

編集2:次の環境設定でレジストリを実行する必要がある場合があります。

REGISTRY_STORAGE_DELETE_ENABLED="true"

EDIT3:あなたはこのディスク領域を解放するためにガベージコレクションを実行する必要があります。 https://docs.docker.com/registry/garbage-collection/


3
ここでの他のいくつかの回答は、マニフェスト参照ハッシュを抽出する方法を示しています。これは、タグを何かに変換してに渡すために必要DELETEです。
JamesThomasMoon1979

サポートされていないエラーが発生しました。参考として適切なダイジェスト値を指定しました。
ウィンスター2018

1
@ JamesThomasMoon1979は、参照ハッシュの取得に関する指示で更新されました。
byrnedo 2018

11
V2でもエラーが発生{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
Gadelkareem 2018年

1
編集をチェックしてください@Gadelkareem
byrnedo

17

問題1

これはプライベートDockerレジストリであるとのことですが、おそらく、提供したリンクであるHubレジストリAPI docではなく、Registry APIを確認する必要があります。

問題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"}

これで、そのAPIを使用してタグを削除できます!!

$ 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"}

2
このコマンドが役に立たない理由については、以下の私の回答を参照してください。
Konrad Kleine 2014

2
タグは削除しますが、画像データは削除しません。後者は、タグを削除した後に参照するスクリプトによって実行されます。また、レジストリAPIを使用してタグを削除します。
Konrad Kleine 2014

3
それは各レジストリAPIサーバーの実装次第であり、プロトコルの観点からは存在しません。
Larry Cai

実装次第ですが、正規のregistry画像から画像データを削除する方法を探していました。SSHを使用してスクリプトを実行することは、理想的ではない場合でも機能します。余談ですが、それでも不完全なAPIだと思います。タグを削除することはできますが、GETし/imagesても残りの画像データはすべて表示されます。
レオ

レジストリAPIについて言及していただきありがとうございます。プライベートレジストリ内の画像を削除する方法を探していました。この方法は、実際にディスク領域を解放せずに単に「タグを外す」だけの場合でも、私には十分です。
ハワードリー

16

これは本当に醜いですが、動作します。テキストはレジストリ:2.5.1でテストされます。削除を有効にする構成を更新した後でも、削除をスムーズに機能させることができませんでした。IDを取得するのは非常に難しく、ログインするにはIDを取得する必要がありました。とにかく、次の作品:

  1. コンテナにログイン

    docker exec -it registry sh
    
  2. コンテナーとコンテナーのバージョンに一致する変数を定義します。

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. レジストリディレクトリに移動します。

    cd /var/lib/registry/docker/registry/v2
    
  4. ハッシュに関連するファイルを削除します。

    find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
    
  5. マニフェストを削除します。

    rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
    
  6. ログアウト

    exit
    
  7. GCを実行します。

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. すべてが適切に行われた場合、削除されたblobに関する情報が表示されます。


上記と同じ手順を実行しましたが、Dockerレジストリ{container}のディスク使用量を確認したところ、手順を実行する前と同じように表示されていました。理由は何ですか?
Savio Mathew

動作しません。簡単に確認できます。次の手順を実行してリポジトリを再度プッシュすると、「064794e955a6:Layer already exists」と表示されます
Oduvan

8

正確にそれを行ういくつかのクライアント(Python、Rubyなど)があります。私の好みでは、レジストリをハウスキーピングするためだけに、レジストリサーバーにランタイム(Pythonなど)をインストールすることは持続可能ではありません。


だからdeckschrubber私の解決策です:

go get github.com/fraunhoferfokus/deckschrubber
$GOPATH/bin/deckschrubber

特定の年齢より古い画像は自動的に削除されます。年齢を使用して指定することができ-year-month-day、またはそれらの組み合わせ:

$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000

更新:これはdeckschrubberの短い紹介です。


1
deckschrubber非常に優れています-インストールが非常に簡単で(シングルバイナリ)、名前(正規表現の一致)と年齢でイメージを削除できます。
RichVel

ERRO[0000] Could not delete image! repo=.... tag=latest:/
scythargon 2017

@scythargonは、仕様が正しいかどうかを言うのは不可能です。
ジッタ、

警告:私のリポジトリでは文字通り何もしませんでした。
Richard Warburton

残念ながら、タグのない画像は削除されません。したがって、単一のタグで画像をプッシュし続けると、タグ付けされたものだけがチェックされ、他のタグはチェックされません。
クリスティアン

1

簡単に。

1)docker repoのRepoDigestsに対して次のコマンドを入力する必要があります。

## docker inspect <registry-host>:<registry-port>/<image-name>:<tag>
> docker inspect 174.24.100.50:8448/example-image:latest


[
    {
        "Id": "sha256:16c5af74ed970b1671fe095e063e255e0160900a0e12e1f8a93d75afe2fb860c",
        "RepoTags": [
            "174.24.100.50:8448/example-image:latest",
            "example-image:latest"
        ],
        "RepoDigests": [
            "174.24.100.50:8448/example-image@sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6"
        ],
...
...

$ {digest} = sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

2)レジストリREST APIを使用する

  ##curl -u username:password -vk -X DELETE registry-host>:<registry-port>/v2/<image-name>/manifests/${digest}


  >curl -u example-user:example-password -vk -X DELETE http://174.24.100.50:8448/v2/example-image/manifests/sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

呼び出しを成功させるには、202 Acceptedを取得する必要があります。

3-)ガベージコレクターの実行

docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml

レジストリ —レジストリコンテナ名。

詳細な説明については、リンクの説明をここに入力してください



0

以下のBashスクリプトは、最新のものを除いて、レジストリにあるすべてのタグを削除します。

for D in /registry-data/docker/registry/v2/repositories/*; do
if [ -d "${D}" ]; then
    if [ -z "$(ls -A ${D}/_manifests/tags/)" ]; then
        echo ''
    else
        for R in $(ls -t ${D}/_manifests/tags/ | tail -n +2); do
            digest=$(curl -k -I -s -H -X GET http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/${R} -H 'accept: application/vnd.docker.distribution.manifest.v2+json'  | grep Docker-Content-Digest | awk '{print $2}' )
            url="http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/$digest"
            url=${url%$'\r'}
            curl -X DELETE -k -I -s   $url -H 'accept: application/vnd.docker.distribution.manifest.v2+json' 
        done
    fi
fi
done

この実行後

docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml

この細かいスクリプトの使用方法についてもう少し詳しく説明してもらえますか?
Khalil Gharbaoui、

0

この回答に基づく単純なrubyスクリプト:registry_cleaner

ローカルマシンで実行できます。

./registry_cleaner.rb --host=https://registry.exmpl.com --repository=name --tags_count=4

次に、レジストリマシンでを使用してblobを削除し/bin/registry garbage-collect /etc/docker/registry/config.ymlます。


0

これは、Yavuz Sertの回答に基づくスクリプトです。最新バージョンではないすべてのタグが削除され、それらのタグは950を超えます。

#!/usr/bin/env bash


CheckTag(){
    Name=$1
    Tag=$2

    Skip=0
    if [[ "${Tag}" == "latest" ]]; then
        Skip=1
    fi
    if [[ "${Tag}" -ge "950" ]]; then
        Skip=1
    fi
    if [[ "${Skip}" == "1" ]]; then
        echo "skip ${Name} ${Tag}"
    else
        echo "delete ${Name} ${Tag}"
        Sha=$(curl -v -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://127.0.0.1:5000/v2/${Name}/manifests/${Tag} 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}')
        Sha="${Sha/$'\r'/}"
        curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE "http://127.0.0.1:5000/v2/${Name}/manifests/${Sha}"
    fi
}

ScanRepository(){
    Name=$1
    echo "Repository ${Name}"
    curl -s http://127.0.0.1:5000/v2/${Name}/tags/list | jq '.tags[]' |
    while IFS=$"\n" read -r line; do
        line="${line%\"}"
        line="${line#\"}"
        CheckTag $Name $line
    done
}


JqPath=$(which jq)
if [[ "x${JqPath}" == "x" ]]; then
  echo "Couldn't find jq executable."
  exit 2
fi

curl -s http://127.0.0.1:5000/v2/_catalog | jq '.repositories[]' |
while IFS=$"\n" read -r line; do
    line="${line%\"}"
    line="${line#\"}"
    ScanRepository $line
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.