programing

개인 도커 레지스트리에서 이미지를 삭제하는 방법은 무엇입니까?

oldcodes 2023. 8. 22. 22:28
반응형

개인 도커 레지스트리에서 이미지를 삭제하는 방법은 무엇입니까?

도커 를 운영하고 , 저는 '도커 레지스트리'를 .latest저장소에서.저장소 전체를 삭제하고 싶지 않습니다. 저장소 내부의 일부 이미지만 삭제합니다.API 문서에는 이를 수행하는 방법이 언급되어 있지 않지만, 확실히 가능합니까?

현재 해당 작업에 레지스트리 API를 사용할 수 없습니다.리포지토리 또는 특정 태그만 삭제할 수 있습니다.

일반적으로 리포지토리를 삭제하면 이 리포지토리와 연결된 모든 태그가 삭제됩니다.

태그를 삭제하면 이미지와 태그 간의 연결이 삭제됩니다.

위의 어떤 것도 단일 이미지를 삭제하지 않습니다.디스크에 남아 있습니다.


해결 방법

이 문제를 해결하려면 도커 이미지를 로컬로 저장해야 합니다.

해결 방법은 최신 태그를 제외한 모든 태그를 삭제하여 관련 이미지에 대한 참조를 제거하는 것입니다.그런 다음 이 스크립트실행하여 태그 또는 사용된 이미지의 조상에서 참조하지 않는 모든 이미지를 제거할 수 있습니다.

용어(이미지 및 태그)

대가다같이그은생보오십시각해를래프미지문자음")가 나오는 것을 .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아마 아닐 거예요!

태그를 삭제하면 어떻게 됩니까?

태그를 삭제하는 경우<version1>Docker REST API를 사용하면 다음과 같은 이점을 얻을 수 있습니다.

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

기억:도커는 이미지를 삭제하지 않습니다!이 경우에도 이미지를 삭제할 수 없습니다. 이미지가 삭제되었기 때문입니다.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.

1단계: 리포지토리 나열

$ curl -sS <domain-on-ip>:5000/v2/_catalog

응답 형식은 다음과 같습니다.

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

2단계: 리포지토리 태그 나열

$ curl -sS <domain-on-ip>:5000/v2/<repo>/tags/list

응답 형식은 다음과 같습니다.

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

3단계: 대상 태그의 다이제스트 결정

$ 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헤더가 필요합니다.이 값이 없으면 다른 값이 표시되고 삭제가 실패합니다.

응답 형식은 다음과 같습니다.

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

4단계: 매니페스트 삭제

$ curl -sS -X DELETE <domain-or-ip>:5000/v2/<repo>/manifests/<digest>

5단계: 이미지 가비지 수집

도커 레지스트리 컨테이너에서 다음 명령을 실행합니다.

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

다음은 내 구성입니다.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

의 류해v2레지스트리가 이제 다음을 통해 삭제를 지원합니다.DELETE /v2/<name>/manifests/<reference>.

참조: https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image

<reference>는 서가져올수있다에서 수 .Docker-Content-DigestGET /v2/<name>/manifests/<tag>request는 다음과 같습니다.Accept: application/vnd.docker.distribution.manifest.v2+json헤더가 이 요청에 필요합니다.

이를 활용한 스크립트: https://github.com/byrnedo/docker-reg-tool

삭제 기능이 작동하려면 삭제 기능이 활성화되어 있어야 합니다(REGISTRY_STORAGE_DELETE_ENABLED=true).

디스크 공간을 확보하려면 가비지 수집을 실행해야 합니다.

이것은 정말 못생겼지만 작동합니다, 텍스트는 레지스트리에서 테스트됩니다: 2.5.1.나는 삭제를 활성화하기 위해 구성을 업데이트한 후에도 삭제 작업을 원활하게 수행하지 못했습니다.아이디를 찾기가 정말 어려웠고, 아이디를 얻으려면 로그인을 해야 했고, 뭔가 오해가 있었을 수도 있습니다.어쨌든 다음과 같은 작업이 가능합니다.

  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. 모든 작업이 올바르게 수행된 경우 삭제된 블롭에 대한 일부 정보가 표시됩니다.

문제 1

당신은 그것이 당신의 개인 도커 레지스트리라고 언급했기 때문에 아마도 당신이 제공한 링크인 허브 레지스트리 API 문서 대신 레지스트리 API를 확인해야 할 것입니다.

문제 2

도커 레지스트리 API는 클라이언트/서버 프로토콜이며 백엔드에서 이미지를 제거할지 여부는 서버의 구현에 달려 있습니다. (아마도)

DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)

상세설명

아래에서는 질문에 대한 제가 이해한 바와 같이 설명을 통해 작동하는 방법을 시연합니다.

개인 도커 등록소를 운영하고 있습니다.기본 포트를 사용하고 포트에서 수신 대기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를 사용하여 개인 도커 레지스트리에 있는지 확인할 수 있습니다.

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

정확히 그렇게 하는 몇몇 클라이언트(파이썬, 루비 등)가 있습니다.레지스트리를 보관하기 위해 레지스트리 서버에 런타임(예: Python)을 설치하는 것은 지속 가능하지 않습니다!


제 솔루션도 마찬가지입니다.

go install github.com/fraunhoferfokus/deckschrubber@latest
$GOPATH/bin/deckschrubber

지정된 기간보다 오래된 이미지는 자동으로 삭제됩니다.연령은 다음을 사용하여 지정할 수 있습니다.-year,-month,-day또는 이들의 조합:

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

업데이트: 갑판 고무에 대한 간단한 소개입니다.

다을제외모든태합삭니제다야해를 제외한 해야 하는 입니다.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

regctl여기서 사용되는 명령은 regclientregctl tag rm로직은 먼저 최근에 배포 사양에 추가된 태그 삭제 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에서 삭제 버튼을 클릭하고 한 번에 이미지 페이지를 삭제한 다음 나중에 쓰레기를 수집하는 것이 더 쉽다는 것을 알게 되었습니다.

간략하게;

도커 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"
        ],
...
...

${filename} = sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa2fecf4f47695e6

레지스트리 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

레지스트리 - 레지스트리 컨테이너 이름입니다.

자세한 설명은 여기에 링크 설명을 입력하십시오.

사용할 수 있는 또 다른 도구는 레지스트리-cli입니다.예를 들어, 다음 명령은 다음과 같습니다.

registry.py -l "login:password" -r https://your-registry.example.com --delete

마지막 10개의 이미지를 제외한 모든 이미지가 삭제됩니다.

생성된 날짜만 기준으로 일부 오래된 이미지를 리포지토리에서 제거할 수도 있습니다.

이 작업을 수행하려면 도커 레지스트리 컨테이너를 입력하고 특정 리포지토리에 대한 매니페스트의 수정 목록을 가져옵니다.

ls -latr /var/lib/registry/docker/registry/v2/repositories/YOUR_REPO/_manifests/revisions/sha256/

그런 다음 출력을 요청 내에서 사용할 수 있습니다(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

그리고 물론 그 후에 'garage-collect' 명령을 실행하는 것을 잊지 마십시오.

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

이 도커 이미지에는 원격 v2 레지스트리에서 이미지를 제거하는 데 사용할 수 있는 bash 스크립트가 포함되어 있습니다. https://hub.docker.com/r/vidarl/remove_image_from_registry/

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

registry_cleaner라는 답변을 기반으로 한 간단한 루비 스크립트.

로컬 시스템에서 실행할 수 있습니다.

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

그런 다음 레지스트리 기계에서 블럽을 제거합니다./bin/registry garbage-collect /etc/docker/registry/config.yml.

여기 야부즈 세르트의 대답을 바탕으로 한 대본이 있습니다.최신 버전이 아닌 모든 태그를 삭제하고 해당 태그의 태그가 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

다음을 제외한 모든 항목을 제거하는 스크립트latest안전하지 않은 레지스트리의 태그(개인, 인증 없음):

#!/bin/sh -eu
repo=$1
registry=${2-localhost:5000}

tags=`curl -sS "$registry/v2/$repo/tags/list" | jq -r .tags[]`
tag2digest() {
    local tag=$1
    curl -sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \
        -o /dev/null \
        -w '%header{Docker-Content-Digest}' \
        "$registry/v2/$repo/manifests/$tag"
}
latest_digest=`tag2digest latest`
digests=`echo "$tags" \
    | while IFS= read -r tag; do
        tag2digest "$tag"
        echo
    done \
    | sort \
    | uniq`
digests=`echo "$digests" \
    | grep -Fvx "$latest_digest"`
echo "$digests" \
    | while IFS= read -r digest; do
        curl -sS -X DELETE "$registry/v2/$repo/manifests/$digest"
    done

용도:

$ ./rm-tags.sh <image> [<registry>]

태그(또는 매니페스트)를 제거한 후 가비지 수집을 실행합니다.

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

도커 허브 및/또는 인증을 지원하려면 다음 답변을 참조하십시오.

이것은 군집 클러스터의 개인 레지스트리를 사용하여 설정에 효과적인 가장 간단한 솔루션입니다.

필요한 필터를 사용한 실험

docker images | grep 'your_own_filter'

tail -n +4의 이미지를 합니다.

awk '{print $3}'세 ' ID 번를 'IMAGE ID'를 합니다.

예:

docker rmi $(docker images | grep 'your_own_filter' | tail -n +4 | awk '{print $3}')

언급URL : https://stackoverflow.com/questions/25436742/how-to-delete-images-from-a-private-docker-registry

반응형