Очистка места в private docker-registry

Не так давно обнаружились проблемы с очисткой места, которое занимают собранные docker-образы в настроенном нами docker-registry — давайте разберемся!

Выяснилось, что в веб-интерфейсе Gitlab на вкладке Registry при нажатии на кнопку «удалить» на самом деле происходит удаление только тэга образа, а сами данные никуда не деваются и продолжают занимать место на жестком диске.

Аналогичная проблема наблюдается если docker-образ создается с одним и тем же тэгом (например, latest) — а это обычное дело для процесса CI. В этом случае, при сборке нового образа старый не удаляется (как ожидается), у него просто пропадает тэг (latest).

Например, у образа master/lebed/test:latest на самом деле на жестком диске хранится 2 версии:

ls -la /srv/gitlab/shared/registry/docker/registry/v2/repositories/master/lebed/test/_manifests/tags/latest/index/sha256
total 16
drwxr-xr-x 4 root root 4096 Jun 15 12:20 .
drwxr-xr-x 3 root root 4096 Jun 15 09:25 ..
drwxr-xr-x 2 root root 4096 Jun 15 12:20 694a3871d67d64d5c59d3f6943be3cfc0d11aae2082261735e87b1c3c58bd66b
drwxr-xr-x 2 root root 4096 Jun 15 09:25 e1f5741ced3f0280bd372baa6ca293d1033dfefc7db021cd81ca1527d2f1c08e

При частых сборках docker-образов отведенное место в docker-registry может закончиться — при этом невозможно будет пушить в него новые образы и весь процесс CI перестанет работать.

Для очистки места в приватном docker-registry необходимо выполнить следующие действия:

  • удалить старые версии тегов docker-образа;
  • удалить старые версии ревизий docker-образа;
  • запустить процесс «уборки мусора» в контейнере с docker-registry.

Рассмотрим подробнее пример выполнения данных действий. Находясь на docker-хосте, смотрим содержимое каталога с интересующим нас docker-образом и его тэгом в каталоге /srv/gitlab/shared/registry/docker/registry/v2/repositories/{имя_докер_образа}/_manifests/tags/{тег_образа}/index/sha256 В нем должны находиться один или несколько каталогов вида e1f5741ced3f0280bd372baa6ca293d1033dfefc7db021cd81ca1527d2f1c08e. Если каталог один, то никаких действий производить не следует, если же таких директорий несколько, то нужно удалить все старые версии, оставив только одну, самую последнюю по дате создания.

Смотрим содержимое каталога с ревизиями интересующего нас docker-образа /srv/gitlab/shared/registry/docker/registry/v2/repositories/{имя_докер_образа}/_manifests/revisions/sha256 В нем должны также быть вложены директории с именами вида e1f5741ced3f0280bd372baa6ca293d1033dfefc7db021cd81ca1527d2f1c08e — точно такие же, как и в предыдущем шаге. Удаляем более старые (ориентируемся по дате создания), оставляя только один каталог.

После удаления вышеуказанных файлов запускаем процесс «уборки мусора» командой:

docker exec -it {имя_контейнера_c_registry} bin/registry garbage-collect {путь_к_конфигу_внутри_контейнера}

В нашем случае команда выглядит так:

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

Для чистки места также можно использовать скрипт clean_docker_registry.sh следующего содержания:

#!/bin/sh
REPOPATH=/srv/gitlab/shared/registry/docker/registry/v2/repositories/
echo Docker image name is $1
echo Docker image tag is $2
echo "\n";
TAGPATH=$REPOPATH$1/_manifests/tags/$2/index/sha256
REVPATH=$REPOPATH$1/_manifests/revisions/sha256
for hash in $(ls $TAGPATH -t | tail -n +2)
do
  rm -rf $TAGPATH/$hash;
  rm -rf $REVPATH/$hash;
done
docker exec -it docker-registry bin/registry garbage-collect /etc/docker/registry/config.yml

Запускаем скрипт с параметрами, первый из которых — имя docker-образа, второй — тэг docker-образа, например:

./clean_docker_registry.sh master/lebed/test latest