개인 도커 레지스트리를 실행 latest
하고 리포지토리에서 이미지를 제외한 모든 이미지를 삭제하고 싶습니다 . 전체 저장소를 삭제하고 싶지 않으며 그 안에있는 이미지 중 일부만 삭제하고 싶습니다. API 문서는 이 작업을 수행 할 수있는 방법을 언급하지 않지만, 분명히 그것은 가능?
개인 도커 레지스트리를 실행 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>
기억하십시오 : Docker는 이미지를 절대 삭제하지 않습니다! 이 경우에도 C
이미지 D
는 태그가 지정된 이미지의 상위 항목 이므로 이미지를 삭제할 수 없습니다 .
이 스크립트 를 사용하더라도 이미지는 삭제되지 않습니다.
누군가가 레지스트리를 가져 오거나 푸시 할 수있는시기를 제어 할 수있는 조건 하에서 (예 : REST 인터페이스 비활성화). 이미지를 기반으로하는 다른 이미지가없고 이미지를 참조하지 않는 경우 이미지 그래프에서 이미지를 삭제할 수 있습니다.
다음 그래프, 이미지가 통지 D
되어 있지 기반으로 C
하지만,에 B
. 따라서에 D
의존하지 않습니다 C
. <version1>
이 그래프에서 태그를 삭제 하면 이미지 C
가 이미지 를 사용하지 않으며이 스크립트 는이를 제거 할 수 있습니다.
A <- B <--------- D
\ |
\ <version2>
\ <latest>
\ <- C
|
<version1>
정리 후 이미지 그래프는 다음과 같습니다.
A <- B <- D
|
<version2>
<latest>
이것이 당신이 원하는 것입니까?
내 레지스트리와 동일한 문제에 직면 한 다음 블로그 페이지에서 아래 나열된 솔루션을 시도했습니다. 효과가있다.
이 URL을 호출하여 카탈로그를 나열 할 수 있습니다.
http://YourPrivateRegistyIP:5000/v2/_catalog
응답 형식은 다음과 같습니다.
{
"repositories": [
<name>,
...
]
}
이 URL을 호출하여 카탈로그의 태그를 나열 할 수 있습니다.
http://YourPrivateRegistyIP:5000/v2/<name>/tags/list
응답 형식은 다음과 같습니다.
{
"name": <name>,
"tags": [
<tag>,
...
]
}
docker registry container에서이 명령을 실행할 수 있습니다.
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
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/...
" 에 대한 메시지를 포함하여 명령이 성공 했지만 사용 된 디스크 공간을 변경하지 않았습니다. 사용 빈 / 레지스트리 github.com/docker/distribution의 v2.4.1을 .
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)}'
현재 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 : 다음 env 세트로 레지스트리를 실행해야 할 수도 있습니다.
REGISTRY_STORAGE_DELETE_ENABLED="true"
Edit3 :이 디스크 공간을 확보하기 위해 가비지 수집을 실행해야 할 수도 있습니다 : https://docs.docker.com/registry/garbage-collection/
DELETE
.
{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
문제 1
개인 도커 레지스트리라고 언급 했으므로 제공 한 링크 인 Hub registry API doc 대신 Registry API 를 확인해야합니다 .
문제 2
docker registry 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}
그런 다음 Registry 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"}
registry
이미지 에서 이미지 데이터를 삭제하는 방법을 찾고있었습니다 . 스크립트가 이상적이지 않더라도 SSH를 실행하고 실행하는 것이 좋습니다. 참고로 여전히 불완전한 API라고 생각합니다. 태그를 삭제할 수 있지만 GET /images
을 사용하면 남은 이미지 데이터가 모두 표시됩니다.
이것은 실제로 추악하지만 작동하지만 텍스트는 레지스트리에서 테스트되었습니다 : 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
GC를 실행하십시오.
docker exec -it registry bin/registry garbage-collect /etc/docker/registry/config.yml
모든 작업이 올바르게 완료되면 삭제 된 얼룩에 대한 정보가 표시됩니다.
정확히 수행하는 클라이언트 (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에 대한 간단한 소개 입니다.
deckschrubber
설치가 매우 쉽고 (단일 바이너리), 이름 (정규식 일치)과 나이로 이미지를 삭제할 수 있습니다.
ERRO[0000] Could not delete image! repo=.... tag=latest
: /
간단히;
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
registry — 레지스트리 컨테이너 이름입니다.
자세한 설명을 보려면 여기에 링크 설명을 입력하십시오
이 도커 이미지에는 원격 v2 레지스트리에서 이미지를 제거하는 데 사용할 수있는 bash 스크립트가 포함되어 있습니다. https://hub.docker.com/r/vidarl/remove_image_from_registry/
Bash Script 아래 최신을 제외한 레지스트리에있는 모든 태그를 삭제합니다.
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
.
다음은 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