Оптимизация хранения образов в реестре 2026: советы и лучшие практики | AdminWiki

Оптимизация хранения образов в реестре 2026: советы и лучшие практики

03 августа 2026 10 мин. чтения

Реестр контейнерных образов без настроенных политик очистки и продуманной структуры сборок неизбежно превращается в свалку гигабайтов устаревших артефактов. Типичный продакшен-реестр среднего размера может содержать до 60% неиспользуемых данных: старые билды, дублирующиеся слои и образы без тегов. Результат - перерасход дискового пространства, замедление CI/CD-пайплайнов и лишние расходы на облачный egress-трафик.

В этом руководстве разобраны три ключевых направления оптимизации: сокращение размера образов через многоэтапную сборку и выбор минимального базового образа, настройка автоматической очистки мусора в Docker Registry и Harbor, внедрение стратегии тегирования, исключающей хаос. Каждый метод подкреплён конкретными командами, конфигурациями и цифрами экономии, которые вы сможете применить сразу после прочтения.

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

Рост реестра происходит по трём причинам. Первая - накопление идентичных слоёв от разных сборок, когда разработчики не используют кэширование и пересобирают образы с нуля. Вторая - отсутствие политик хранения: каждый новый пуш добавляет тег, старые не удаляются. Третья - бесконтрольное использование тега latest, при котором образ перезаписывается, а старый манифест остаётся в хранилище как мусор.

Без регулярной очистки реестр из 100 ГБ может содержать 30-40 ГБ неиспользуемых данных уже через три месяца активной разработки. Диагностика начинается с аудита текущего состояния.

Инструменты для аудита: от docker system df до скриптов

Для локальной оценки использования диска Docker-демоном выполните команду:

docker system df -v

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

Для анализа удалённого Docker Registry используйте Catalog API. Получите список всех репозиториев:

curl -s https://registry.example.com/v2/_catalog

Затем для каждого репозитория запросите список тегов:

curl -s https://registry.example.com/v2/myapp/tags/list

Размер конкретного манифеста извлекается через HEAD-запрос к манифесту и анализ заголовка Content-Length. Скрипт для подсчёта суммарного объёма всех образов в registry может выглядеть так:

#!/bin/bash
REGISTRY="https://registry.example.com"
TOTAL_SIZE=0

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[]?')
  for tag in $TAGS; do
    SIZE=$(curl -sI "$REGISTRY/v2/$repo/manifests/$tag" \
      -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
      | grep -i content-length | awk '{print $2}' | tr -d '\r')
    TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
  done
done
echo "Total size: $((TOTAL_SIZE / 1024 / 1024)) MB"

В Harbor диагностика встроена в административную панель. Раздел Administration → Garbage Collection показывает объём освобождаемого места после последней сборки мусора. На вкладке Projects для каждого проекта отображается количество артефактов и занимаемый объём. Детальный разбор архитектуры слоёв и поиск «тяжёлых» образов удобно выполнять утилитой dive - она показывает каждый слой в интерактивном режиме и подсвечивает неэффективно использованное пространство. Подробнее об анализе слоёв с dive и docker inspect читайте в руководстве по архитектуре Docker-образов.

Стратегия уменьшения размера образов: от Dockerfile до production

Сокращение размера образа - прямой путь к ускорению пайплайнов и снижению нагрузки на реестр. Образ весом 1.2 ГБ выкачивается из реестра за 40-60 секунд при гигабитном канале, а его 150-мегабайтный аналог - за 5-7 секунд. В масштабе сотни деплоев в день разница превращается в часы простоя и гигабайты лишнего трафика.

Многоэтапная сборка: пошаговый разбор и лучшие практики

Multi-stage build решает проблему артефактов сборки, которые не нужны в рантайме. Dockerfile делится на этапы: первый компилирует код и собирает зависимости, второй копирует только готовый бинарник или минимальный набор файлов.

Пример для Go-приложения:

# Этап сборки
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .

# Этап выполнения
FROM alpine:3.20
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/server /usr/local/bin/server
USER 1000
ENTRYPOINT ["server"]

Финальный образ содержит только бинарник и сертификаты - около 15 МБ вместо 800+ МБ полного образа golang с исходниками и тулчейном. Именование этапов через AS builder улучшает читаемость, когда этапов больше двух.

Для интерпретируемых языков многоэтапная сборка тоже эффективна. Пример для Node.js:

FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY src/ ./src/
USER node
CMD ["node", "src/index.js"]

Здесь на первом этапе устанавливаются только production-зависимости, на втором - копируются модули и исходный код. devDependencies и npm-кэш в образ не попадают. Готовые шаблоны Dockerfile для Python, Node.js и Go с multi-stage сборкой и настройками безопасности собраны в подборке проверенных Dockerfile 2026.

Выбор базового образа: alpine, slim или distroless?

Базовый образ определяет нижнюю границу размера. Сравнение для типового приложения:

Базовый образРазмерОсобенности
ubuntu:22.04~77 МБПолный дистрибутив, glibc, apt, shell
debian:bookworm-slim~28 МБУрезанный Debian, glibc, shell
alpine:3.20~3 МБmusl libc, ash, apk
gcr.io/distroless/static-debian12~2 МБТолько рантайм, нет shell, нет пакетного менеджера

Выбор зависит от сценария. Alpine даёт минимальный размер при наличии shell для отладки, но использует musl libc - это источник трудноуловимых багов с C-расширениями Python или Node.js, собранными под glibc. Slim-образы Debian сохраняют совместимость с glibc и весят вдвое меньше полных версий. Distroless от Google содержит только runtime-зависимости и ваш код - максимальная безопасность и минимальный размер, но отсутствие shell усложняет отладку.

Рекомендация для production: начните с distroless, если приложение не требует shell-доступа. Для отладки держите отдельный debug-образ на базе alpine с установленным curl и busybox. Подробнее о стратегиях очистки неиспользуемых образов в production-окружениях читайте в руководстве по управлению Docker-образами в продакшене.

Настройка автоматической очистки: политики хранения и garbage collection

Ручная очистка реестра нежизнеспособна при активной разработке. Автоматизация решает проблему на двух уровнях: политики хранения определяют, какие образы удалять, сборка мусора физически освобождает место на диске. Без garbage collection удалённый манифест продолжает занимать место в хранилище - это особенность архитектуры Docker Registry, где удаление лишь разрывает ссылку, но не трогает blob-файлы.

Политики хранения в Harbor: настройка без ошибок

Harbor предоставляет гибкий механизм retention policies на уровне проекта. Настройка выполняется в веб-интерфейсе: откройте проект, перейдите на вкладку Policy, создайте новое правило.

Ключевые параметры правила:

  • Scope - фильтр по имени репозитория или тегам. Например, feature/** для всех feature-веток или release-* для релизных сборок.
  • Retention rules - сколько артефактов оставлять. Можно указать «хранить 5 последних образов» или «удалять образы, не скачивавшиеся 14 дней».
  • Schedule - расписание выполнения: cron-выражение или ежедневно/еженедельно.

Рабочий пример для команды из 10 разработчиков:

  • Для тега main-* хранить последние 10 сборок - покрывает откат на неделю назад.
  • Для тегов feature/* удалять образы старше 7 дней - feature-ветки живут недолго.
  • Для тега latest хранить 3 версии - защита от случайной перезаписи.

Перед включением политики проверьте список кандидатов на удаление: в интерфейсе Harbor есть кнопка Dry Run, которая показывает, какие артефакты попадут под правило, но не удаляет их.

Очистка в Docker Registry: скрипты и ручное управление

Стандартный Docker Registry не имеет встроенных политик хранения. Процесс очистки состоит из трёх шагов: получить список тегов через API, удалить манифест, запустить garbage collection.

Удаление манифеста выполняется запросом:

curl -X DELETE https://registry.example.com/v2/myapp/manifests/sha256:abc123... \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json"

Для получения digest нужного тега сначала запросите манифест с заголовком Accept, в ответе придёт заголовок Docker-Content-Digest.

После удаления манифестов запустите сборку мусора внутри контейнера registry:

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

Эта операция требует перевода registry в read-only режим или полной остановки - garbage collection блокирует хранилище на время работы. Для реестра объёмом 50 ГБ процесс занимает 2-5 минут.

Готовый скрипт для удаления образов старше 30 дней:

#!/bin/bash
REGISTRY="https://registry.example.com"
CUTOFF_DATE=$(date -d '30 days ago' +%s)

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[]?')
  for tag in $TAGS; do
    # Пропускаем latest и release-теги
    if [[ "$tag" == "latest" || "$tag" == release-* ]]; then continue; fi
    CONFIG_DIGEST=$(curl -sI "$REGISTRY/v2/$repo/manifests/$tag" \
      -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
      | grep docker-content-digest | awk '{print $2}' | tr -d '\r')
    CREATED=$(curl -s "$REGISTRY/v2/$repo/blobs/$CONFIG_DIGEST" | jq -r '.created')
    CREATED_TS=$(date -d "$CREATED" +%s)
    if [ $CREATED_TS -lt $CUTOFF_DATE ]; then
      curl -X DELETE "$REGISTRY/v2/$repo/manifests/$CONFIG_DIGEST"
      echo "Deleted $repo:$tag"
    fi
  done
done
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml

Скрипт пропускает теги latest и release-*, чтобы не затронуть production-образы. Перед первым запуском сделайте бэкап директории хранения registry - обычно это /var/lib/registry внутри контейнера. Комплексный подход к очистке Docker-окружения, включая удаление контейнеров и томов, описан в инструкции по полной очистке Docker.

Эффективное тегирование: как перестать плодить мусор

Тег latest - главный источник проблем. Он не указывает на конкретную версию, перезаписывается при каждом пуше и делает невозможным откат. В production-окружении образ должен идентифицироваться однозначно.

Рабочая стратегия тегирования для CI/CD:

  • Семантическое версионирование: 1.2.3, 1.2.3-hotfix1. Подходит для релизных сборок, позволяет быстро найти нужную версию.
  • Git-коммит: main-abc1234, feature-login-def5678. Каждый образ привязан к конкретному коммиту - полная воспроизводимость.
  • Окружение: staging, prod. Плавающие теги, которые всегда указывают на актуальный образ в окружении. Используйте только для окружений, где допустима автоматическая смена версии.

Для production-деплоев комбинируйте подходы: деплойте по иммутабельному тегу (git-коммит или версия), а тег prod обновляйте атомарно после успешного деплоя. Это даёт возможность мгновенного отката - достаточно переключить prod на предыдущую версию.

Политики очистки напрямую завязаны на теги. Правило «хранить 5 последних образов с тегом release-*» работает только при последовательном тегировании. Если все образы помечены как latest, политика хранения бесполезна - она не сможет отличить вчерашний билд от позавчерашнего.

Ускорение развертывания: как размер образа влияет на CI/CD

Время выкачивания образа из реестра - прямой множитель длительности деплоя. Образ размером 1 ГБ при канале 100 Мбит/с загружается 80 секунд. Тот же образ, оптимизированный до 100 МБ - 8 секунд. При 50 деплоях в день экономия составляет час чистого времени ожидания.

Кэширование слоёв в Docker работает на уровне отдельных инструкций Dockerfile. Слой пересобирается, только если изменилась инструкция или файлы, которые она копирует. Правильный порядок инструкций в Dockerfile ускоряет сборку:

# Часто меняющиеся файлы - в конец
COPY package.json package-lock.json ./
RUN npm ci
COPY src/ ./src/  # Исходный код меняется чаще, чем зависимости

При таком порядке слой с npm ci пересобирается только при изменении lock-файла, а не при каждом изменении исходников. В облачных средах каждый гигабайт egress-трафика из реестра тарифицируется. Для AWS ECR это $0.09/ГБ после первого гигабайта в месяц. Реестр, генерирующий 500 ГБ исходящего трафика, экономит $45/месяц при сокращении размера образов вдвое.

Профилактика и мониторинг: чтобы реестр не пух снова

Оптимизация - не разовая акция. Реестр требует регулярного обслуживания, встроенного в процессы команды.

Настройте мониторинг свободного места. Для Harbor метрики доступны через Prometheus-эндпоинт /metrics. Ключевые метрики: harbor_project_quota_usage_byte - использование квот по проектам, harbor_disk_free - свободное место на диске. Настройте алерт в Grafana при заполнении диска выше 80%.

Встройте проверку размера образа в CI-пайплайн. Добавьте шаг после сборки:

IMAGE_SIZE=$(docker image inspect myapp:latest --format='{{.Size}}')
MAX_SIZE=524288000  # 500 MB in bytes
if [ $IMAGE_SIZE -gt $MAX_SIZE ]; then
  echo "Image size $IMAGE_SIZE exceeds limit $MAX_SIZE"
  exit 1
fi

Это предотвращает попадание раздутых образов в реестр. Порог в 500 МБ разумен для большинства приложений - если образ превышает лимит, разработчик должен обосновать исключение или оптимизировать Dockerfile.

Проводите ежемесячный аудит с помощью скрипта из первого раздела. Сравнивайте динамику: если объём реестра растёт быстрее, чем количество сервисов, политики очистки требуют пересмотра. Проблема утечек дискового пространства не ограничивается Docker-образами - логи, снапшоты и временные файлы тоже требуют внимания. Системный подход к диагностике описан в руководстве по борьбе с утечками дискового пространства.

Формируйте культуру работы с образами в команде: договоритесь о максимальном размере образа, зафиксируйте соглашение по тегированию в CONTRIBUTING.md репозитория, назначьте ответственного за ежемесячный аудит реестра. Эти практики окупаются стабильностью пайплайнов и предсказуемыми расходами на хранение.

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