Очистка реестра образов: полное руководство по удалению неиспользуемых данных | AdminWiki

Очистка реестра образов: полное руководство по удалению неиспользуемых данных

03 августа 2026 11 мин. чтения
Содержание статьи

Реестр контейнерных образов без регулярной очистки неизбежно превращается в цифровую свалку. Вы сталкиваетесь с ошибками no space left on device в самый неподходящий момент - во время деплоя, когда каждая секунда простоя стоит денег. Падает скорость push/pull, растут счета за облачное хранилище, а CI/CD пайплайны работают медленнее. Решение - настроить автоматическую очистку и освоить ручное удаление неиспользуемых данных. В этом руководстве собраны проверенные команды и стратегии для Docker Registry, Harbor и GitLab Container Registry, которые помогут освободить гигабайты дискового пространства без риска для production.

Перед любыми манипуляциями с реестром сделайте бэкап директории хранения и конфигурационного файла. Переведите реестр в read-only режим. Проведите аудит неиспользуемых образов с помощью reg или skopeo. Запустите dry-run garbage collection и только после этого приступайте к физическому удалению. Такой подход исключает потерю критичных данных и даёт полный контроль над процессом.

Зачем чистить реестр: типичные проблемы и их последствия

По данным внутренних аудитов инфраструктур, до 40% образов в реестрах не используются дольше 30 дней. Это промежуточные билды, теги feature-веток, устаревшие версии с меткой latest. Каждый такой образ занимает место и замедляет работу всего кластера.

Первый симптом захламления - ошибка no space left при push новой версии. Деплой останавливается, команда тратит время на экстренную очистку. Второй симптом - рост времени выполнения pull. Когда в реестре сотни гигабайт мусора, операции с метаданными замедляются. Третий - финансовый. Облачные хранилища (S3, GCS, Azure Blob) тарифицируются по объёму, и каждый неиспользуемый слой увеличивает ежемесячный счёт.

Влияние на CI/CD пайплайны прямое: сборка, которая раньше занимала 3 минуты, растягивается до 7-10 из-за долгого получения метаданных. Разработчики ждут, релизный цикл удлиняется. Регулярная очистка реестра - это не разовая акция, а обязательная часть эксплуатации, как и оптимизация хранения образов.

Архитектура реестра: что именно мы удаляем

Безопасное удаление невозможно без понимания модели хранения Docker Registry v2. Реестр оперирует тремя типами артефактов: теги, манифесты и слои. Связь между ними определяет, что можно удалить без последствий, а что - нельзя.

Манифест - это JSON-документ, описывающий образ. Он содержит список слоёв (blob'ов) и их хеши. Слой - это tar-архив с изменениями файловой системы относительно предыдущего слоя. Тег - указатель на конкретный манифест. Один манифест может иметь несколько тегов (v1.0, latest, stable), и все они ссылаются на один и тот же набор слоёв.

Когда вы удаляете тег, манифест и связанные с ним слои не удаляются автоматически. Они остаются в хранилище как «осиротевшие» (orphaned) до запуска Garbage Collection. Если на манифест ссылаются другие теги, удаление одного тега не затрагивает данные - это ключевой принцип безопасности.

Теги, манифесты и слои: иерархия артефактов

Тег - это человекочитаемая метка, указывающая на digest манифеста. При выполнении docker pull myapp:1.0 клиент запрашивает у реестра манифест по тегу, затем скачивает слои, перечисленные в этом манифесте. Команда docker manifest inspect myapp:1.0 показывает полную структуру: digest манифеста, список слоёв с их размерами и контрольными суммами.

Манифест идентифицируется по digest'у - SHA256-хешу содержимого. Это неизменяемый идентификатор. Тег - изменяемый указатель. Переместить тег latest на новый манифест можно без удаления старого манифеста, и он останется в хранилище, если на него больше никто не ссылается.

Слой (blob) хранится один раз, даже если используется в десятках образов. Это работает благодаря контентно-адресуемому хранилищу: имя файла слоя - его SHA256-хеш. При удалении манифеста GC проверяет, ссылается ли на каждый слой хотя бы один другой манифест. Если нет - слой помечается как удалённый.

Как работает Garbage Collection в Docker Distribution

Garbage Collection (GC) в Docker Distribution - двухэтапный процесс. Первый этап - пометка: вы удаляете тег или манифест через API, и он исчезает из листинга, но файлы остаются на диске. Второй этап - физическая очистка: запуск registry garbage-collect сканирует все оставшиеся манифесты, строит множество используемых blob'ов и удаляет всё, что не входит в это множество.

Без запуска GC место не освобождается. Удалили 50 тегов - свободное пространство не изменилось ни на байт. Только после bin/registry garbage-collect /etc/docker/registry/config.yml файлы физически удаляются с диска. В продакшене GC рекомендуется запускать в режиме read-only, чтобы избежать гонки данных между удалением и push новых образов.

Для сложных сценариев, когда нужно выявить корневую причину захламления, может потребоваться диагностика утечек дискового пространства на уровне всей системы.

Подготовка к очистке: аудит и меры безопасности

Очистка реестра без подготовки - прямой путь к инциденту. Удаление не того тега может остановить деплой критичного сервиса. Чек-лист из четырёх шагов снижает риск до минимума.

Шаг первый - бэкап. Сохраните директорию хранения данных и конфигурационный файл реестра. Шаг второй - переведите реестр в read-only режим, чтобы никто не мог push'ить новые образы во время очистки. Шаг третий - проведите аудит: определите, какие образы используются в CI/CD пайплайнах, какие запрашивались за последние 30 дней, какие имеют теги <none>. Шаг четвёртый - выполните dry-run удаления и проанализируйте, сколько места освободится.

Бэкап реестра: что и как сохранять

Стандартная директория хранения Docker Registry - /var/lib/registry. В ней находятся поддиректории docker/registry/v2/repositories (метаданные и манифесты) и docker/registry/v2/blobs (слои). Для бэкапа достаточно создать архив этой директории вместе с конфигурационным файлом:

tar -czf registry-backup-$(date +%Y%m%d).tar.gz /var/lib/registry /etc/docker/registry/config.yml

Для крупных инсталляций (сотни гигабайт) используйте инкрементальный бэкап через restic или rsync. Restic создаёт снапшоты с дедупликацией и поддерживает шифрование:

restic -r /mnt/backup-repo backup /var/lib/registry

Проверьте целостность бэкапа перед началом очистки. Попытка восстановить реестр из битого архива после неудачного удаления оставит вас без данных.

Аудит неиспользуемых образов: инструменты и критерии

Для аудита применяются три инструмента: reg - утилита для работы с API реестра, skopeo - для инспектирования образов без их загрузки, и прямые HTTP-запросы к Registry API через curl.

Критерии для определения неиспользуемых образов:

  • Теги <none> - dangling-образы, потерявшие ссылку при перезаписи тега.
  • Образы старше 30 дней без pull'ов - определяются по логам реестра или метрикам.
  • Теги feature-веток после мерджа - временные артефакты CI/CD.
  • Промежуточные билды с хешем коммита, если хранится финальный production-тег.

Пример команды для поиска образов без тегов через API Docker Registry:

curl -s https://registry.example.com/v2/_catalog | jq -r '.repositories[]' | while read repo; do
  curl -s "https://registry.example.com/v2/$repo/tags/list" | jq -r '.tags[]?' | grep -q . || echo "$repo: no tags"
done

Для более детального анализа используйте reg - она показывает digest, размер и дату создания каждого тега. Скрипт, собирающий эту информацию в CSV, упрощает принятие решений о том, что удалять.

Пошаговая очистка Docker Registry

Процесс очистки стандартного Docker Distribution состоит из трёх этапов: удаление тегов через API, запуск Garbage Collection и верификация результата. Каждый этап описан с конкретными командами и ожидаемым выводом.

Удаление тегов через Registry API

Для удаления тега нужно сначала получить digest манифеста, на который он указывает. Это делается GET-запросом с заголовком Accept, указывающим на формат манифеста:

curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  https://registry.example.com/v2/myapp/manifests/old-tag \
  -o /dev/null -w '%header{Docker-Content-Digest}'

Полученный digest (например, sha256:abc123...) используется в DELETE-запросе:

curl -X DELETE https://registry.example.com/v2/myapp/manifests/sha256:abc123...

Удаление тега не освобождает место. Docker Registry помечает манифест как удалённый, но физические файлы остаются. Если на этот же манифест ссылается другой тег, удаление не произойдёт - API вернёт ошибку MANIFEST_UNKNOWN или просто проигнорирует запрос.

Запуск Garbage Collection и проверка результата

Garbage Collection запускается из командной строки на хосте, где работает реестр. Рекомендуется сначала выполнить dry-run для оценки объёма освобождаемого пространства:

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

Вывод покажет список blob'ов, которые будут удалены, и суммарный размер. Пример вывода:

blobs marked for deletion: 247
space reclaimed: 12.3 GB

Физическая очистка запускается той же командой без флага --dry-run. Перед этим реестр должен быть переведён в read-only режим или остановлен. После завершения GC проверьте освобождённое место через df -h и убедитесь, что реестр корректно отвечает на запросы /v2/_catalog.

Если после очистки остались проблемы с производительностью, обратитесь к руководству по оптимизации хранения образов - там разобраны стратегии уменьшения размера образов на этапе сборки.

Автоматизация очистки: политики и cron-задачи

Ручная очистка реестра каждую неделю - потеря времени. Автоматизация через скрипты и cron-задачи превращает разовую операцию в системный процесс. Правильно настроенная политика хранения предотвращает повторное захламление.

Пример скрипта для автоматического удаления старых тегов

Скрипт ниже получает список всех репозиториев, для каждого оставляет последние 5 тегов (по алфавиту, что соответствует семантическому версионированию) и удаляет остальные. Зависимости: curl, jq.

#!/bin/bash
REGISTRY="https://registry.example.com"
KEEP=5

repos=$(curl -s "$REGISTRY/v2/_catalog" | jq -r '.repositories[]')

for repo in $repos; do
  tags=$(curl -s "$REGISTRY/v2/$repo/tags/list" | jq -r '.tags[]?' | sort -r)
  count=$(echo "$tags" | wc -l)
  if [ "$count" -gt "$KEEP" ]; then
    to_delete=$(echo "$tags" | tail -n +$((KEEP+1)))
    for tag in $to_delete; do
      digest=$(curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        "$REGISTRY/v2/$repo/manifests/$tag" \
        -o /dev/null -w '%header{Docker-Content-Digest}')
      curl -s -X DELETE "$REGISTRY/v2/$repo/manifests/$digest"
      echo "Deleted: $repo:$tag"
    done
  fi
done

Скрипт не удаляет теги, если их меньше или равно KEEP. Это защищает репозитории с малым количеством версий от полной очистки. Для production-сред добавьте проверку, что тег не используется в запущенных контейнерах.

Интеграция с CI/CD: очистка после сборки

Встраивание очистки в пайплайн решает проблему накопления временных образов. После мерджа feature-ветки соответствующий тег в реестре больше не нужен. Пример stage для GitLab CI:

cleanup_feature_image:
  stage: cleanup
  script:
    - |
      DIGEST=$(curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        "$CI_REGISTRY/v2/$CI_PROJECT_PATH/manifests/$CI_COMMIT_REF_SLUG" \
        -o /dev/null -w '%header{Docker-Content-Digest}')
      curl -s -X DELETE "$CI_REGISTRY/v2/$CI_PROJECT_PATH/manifests/$DIGEST"
  only:
    - merge_requests

Переменные $CI_REGISTRY, $CI_PROJECT_PATH и $CI_COMMIT_REF_SLUG подставляются GitLab автоматически. Этот stage выполняется при мердже и удаляет образ feature-ветки, оставляя только production-теги.

Особенности очистки в популярных реестрах

Docker Distribution - не единственный реестр в эксплуатации. Harbor, GitLab Container Registry, AWS ECR и GCR имеют собственные механизмы очистки. Таблица ниже даёт сравнительный обзор, а последующие разделы детализируют настройку для двух самых популярных self-hosted решений.

Реестр Удаление тегов Встроенная политика очистки Особенности GC
Docker Distribution API (DELETE /manifests) Нет Ручной запуск, блокирует реестр
Harbor API + веб-интерфейс Tag Retention Rules Запуск из админки, неделимая операция
GitLab Container Registry API + cleanup policy Cleanup policy в проекте Асинхронный фоновый процесс
AWS ECR CLI + lifecycle policy Lifecycle Policy (правила в JSON) Автоматический, до 24 часов
GCR CLI + lifecycle policy Lifecycle Policy (условия по тегам и датам) Автоматический

Harbor: политики хранения тегов и ручная очистка

Harbor предоставляет встроенный механизм Tag Retention Rules, доступный через веб-интерфейс в разделе Projects → ваш проект → Tag Retention. Правила задаются на уровне проекта и применяются ко всем репозиториям внутри него.

Настройка правила: укажите, сколько последних тегов сохранять (например, 10) и какие теги учитывать (по шаблону v* для версионных тегов). Можно задать несколько правил для разных шаблонов. После сохранения правила запустите симуляцию (Dry Run), чтобы увидеть, какие теги будут удалены, и только затем выполните реальную очистку.

Garbage Collection в Harbor запускается вручную из админки: Administration → Garbage Collection. Это неделимая операция - во время её выполнения реестр недоступен для push/pull. Планируйте GC на окна минимальной нагрузки. Harbor также поддерживает ручное удаление отдельных тегов через веб-интерфейс, что удобно для точечной очистки.

GitLab Container Registry: cleanup policies и ограничения

GitLab Container Registry управляется на уровне проекта. Cleanup policy включается в Settings → Packages and Registries → Cleanup policy. Доступны два типа правил: хранить последние N тегов (keep_n) и удалять теги старше X дней (older_than). Правила комбинируются - можно оставить 5 последних тегов и удалить всё старше 90 дней.

Важный нюанс: очистка в GitLab запускается асинхронно фоновым воркером. Между включением политики и фактическим удалением тегов может пройти несколько часов. Статус выполнения виден в интерфейсе того же раздела. Для ручного запуска GC из консоли GitLab-сервера используется команда:

gitlab-ctl registry-garbage-collect -m

Флаг -m включает режим пометки (mark), который только помечает неиспользуемые blob'ы. Без этого флага GC выполняет полную очистку. В высоконагруженных инсталляциях рекомендуется сначала запустить пометку, проверить логи, и только потом - физическое удаление.

Для обеспечения безопасности реестра после очистки настройте сканирование образов на уязвимости - чистый реестр должен быть ещё и безопасным.

Мониторинг и профилактика: как не допустить повторного захламления

Очистка реестра - это лечение симптома. Профилактика - внедрение метрик, алертов и культуры тегирования, которые предотвращают накопление мусора. Три компонента профилактики описаны ниже.

Метрики реестра и алерты в Prometheus

Docker Distribution предоставляет endpoint /metrics с данными в формате Prometheus. Метрика registry_storage_size_bytes показывает текущий размер хранилища. Настройте сбор этой метрики в Prometheus и создайте алерт на 80% заполнения диска:

groups:
  - name: registry_alerts
    rules:
      - alert: RegistryStorageFillingUp
        expr: registry_storage_size_bytes / node_filesystem_size_bytes{mountpoint="/var/lib/registry"} > 0.8
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Registry storage is over 80% capacity"

Дополнительно отслеживайте количество образов (registry_storage_blobs_total) и скорость роста. Резкий скачок на 20% за сутки сигнализирует о проблеме в CI/CD - например, о сборке без очистки временных тегов.

Рекомендации по тегированию и управлению жизненным циклом образов

Правильное тегирование сокращает необходимость частой очистки на порядок. Три правила, внедрение которых меняет картину:

Первое - используйте уникальные теги для production. Git commit SHA (myapp:abc1234) гарантирует, что каждый деплой ссылается на конкретный билд. Тег latest допустим только в dev-среде, где не важна воспроизводимость.

Второе - автоматически удаляйте теги feature-веток после мерджа. Это реализуется через stage в CI/CD, как показано в разделе выше. Без автоматизации временные образы копятся и занимают десятки гигабайт.

Третье - ограничьте количество хранимых версий. Для большинства проектов достаточно 5-10 последних production-тегов. Старые версии можно восстановить из исходного кода и Dockerfile, если они не используются активными деплоями.

Для комплексного подхода к управлению образами изучите интеграцию реестра с CI/CD пайплайнами - там разобраны стратегии тегирования и автоматической публикации образов.

Поделиться:
Сохранить гайд? В закладки браузера