Я запускаю приватний реєстр докерів, і хочу видалити всі зображення, окрім latest
репозиторію. Я не хочу видаляти весь сховище, лише деякі зображення всередині нього. Документи API не згадують спосіб це зробити, але напевно це можливо?
Я запускаю приватний реєстр докерів, і хочу видалити всі зображення, окрім latest
репозиторію. Я не хочу видаляти весь сховище, лише деякі зображення всередині нього. Документи API не згадують спосіб це зробити, але напевно це можливо?
Відповіді:
В даний час ви не можете використовувати API реєстру для цього завдання. Це дозволяє лише видалити сховище або певний тег.
Загалом, видалення сховища означає, що всі теги, пов'язані з цим репо, видаляються.
Видалення тегу означає, що асоціація між зображенням і тегом видалена.
Жодне з вищезазначеного не видалить жодне зображення. Вони залишаються на вашому диску.
Для цього вирішуйте, що ваші докерські зображення зберігаються локально.
Принциповим рішенням вашого рішення буде видалення всіх, крім останніх тегів, і тим самим потенційно видалення посилання на пов'язані зображення. Потім ви можете запустити цей скрипт, щоб видалити всі зображення, на які не посилається жоден тег чи походження використовуваних зображень.
Розглянемо графік зображення , як це , де великі літери ( A
, B
, ...) представляють собою короткі ідентифікатори зображень і <-
означає , що зображення на основі іншого зображення:
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>
за допомогою API Docker REST, ви отримаєте це:
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:
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
Запустіть цю команду в контейнері реєстру докера:
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
частина повинна бути в нижньому регістрі (перевірено на Docker двигуна 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
Ви згадали, що це ваш приватний реєстр докерів, тому вам, ймовірно, потрібно перевірити API реєстру замість документа API реєстру Hub , що є посиланням, яке ви надали.
Завдання 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"}
registry
зображення. SSHing в і запуск сценарію працює, навіть якщо це не ідеально. Як бічну зауваження, я все ще думаю, що це неповний API - ви можете видалити теги, але якщо ви /images
отримаєте, ви все ще бачите всі дані, що залишилися від зображення.
Це справді некрасиво, але це працює, текст перевіряється в реєстрі: 2.5.1. Мені не вдалося змусити видалення працювати плавно навіть після оновлення конфігурації, щоб увімкнути видалення. Ідентифікатор було важко знайти, довелося увійти, щоб отримати його, можливо, якесь непорозуміння. У будь-якому разі, такі дії:
Вхід у контейнер
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
досить непоганий - дуже простий в установці (одинарний бінарний), і дозволяє видаляти зображення за назвою (із збігом регулярних виразів), а також за віком.
ERRO[0000] Could not delete image! repo=.... tag=latest
: /
Коротко;
1) Ви повинні набрати наступну команду для 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
register - назва контейнера реєстру.
Для більш детального пояснення введіть опис посилання тут
Це зображення докера включає сценарій bash, який можна використовувати для видалення зображень із віддаленого реєстру v2: 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
Простий сценарій рубіну, заснований на цій відповіді: register_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