Cleanup registry

Уровень: advanced ~45 мин Практика: Vikunja (AGPL-3.0)

Что нужно знать перед уроком

  • M3.06 — Секреты сборки и giterminism — нужно понимать полный цикл сборки перед изучением очистки registry

Что нужно знать перед уроком

M3 уроки 1–6 — весь цикл сборки: образы, слои, оба билдера, линковка, секреты. Последний штрих модуля — что происходит с registry после множества сборок, и почему без явной политики очистки он растёт бесконечно.

Теория

Почему registry разрастается без ограничений

Каждый werf build/werf converge в CI (ветка, тег, коммит) публикует новый образ (или новый тег на уже существующий контент, если контент не изменился — content-based тегирование, детально в M8 уроке 3) в registry. Без явной политики удаления старых версий, за месяцы активной разработки Application-пакета с частыми коммитами registry накапливает тысячи образов — большинство из которых физически никому не нужны (промежуточные коммиты давно смерженных и удалённых feature-веток, старые версии main, для которых уже есть новее).

Дефолтные keepPolicies, если вы ничего не настраивали сами

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cleanup:
  keepPolicies:
    - references:
        tag: /.*/
        limit:
          last: 10
    - references:
        branch: /.*/
        limit:
          last: 10
          in: 168h
          operator: And
      imagesPerReference:
        last: 2
        in: 168h
        operator: And
    - references:
        branch: /^(main|master|staging|production)$/
      imagesPerReference:
        last: 2

Три политики применяются одновременно (объединение результатов, а не пересечение — образ сохраняется, если удовлетворяет хотя бы одной политике):

  1. Любой Git-тег (tag: /.*/) — хранить последние 10 (limit.last: 10) образов, привязанных к тегам. Для тегов проверяется только HEAD-коммит (тег указывает на конкретный коммит, в отличие от ветки).
  2. Любая ветка (branch: /.*/) — хранить до 10 последних веток, активных за последние 168 часов (in: 168h = 7 дней, operator: And означает «и последние 10, и активные за 7 дней» одновременно), и для каждой такой ветки — до 2 последних образов (imagesPerReference), собранных за последние 7 дней.
  3. Защищённые ветки (main/master/staging/production, через regex) — отдельное, более мягкое правило: без ограничения на количество/активность самих веток (эти ветки всегда сохраняются), но с ограничением imagesPerReference.last: 2 — хранить только 2 последних образа даже для критичных долгоживущих веток (более старые образы main, если они больше не нужны, всё равно удаляются).

references/imagesPerReference — раздельный контроль

references определяет, какие Git-теги/ветки участвуют в правиле (через точное имя или regex). imagesPerReference определяет, сколько образов на каждую отобранную ссылку сохранять, с параметрами last (количество, по умолчанию 1) и in (временное окно, формат Go duration) и operator (And/Or — как комбинируются last и in, если оба заданы). Раздельность этих двух измерений (какие ссылки vs сколько образов на ссылку) позволяет гибко настраивать: например, «хранить только защищённые ветки, но неограниченно долго» — references без limit, imagesPerReference без in.

werf cleanup — команда и стратегия регулярного запуска

1
werf cleanup --repo registry.mydomain.com/app

werf cleanup анализирует текущую Git-историю проекта, сопоставляет её с образами в registry согласно keepPolicies и безопасно удаляет всё, что не подпадает под сохранение ни одной политикой. «Безопасно» — потому что werf сначала анализирует Git-историю (какие ветки/теги реально существуют сейчас), а не просто удаляет «старые по дате» образы без контекста — образ на активной ветке не будет удалён, даже если формально «старый» по времени публикации, если ветка попадает в keepPolicies.

Рекомендуемая стратегия — гонять werf cleanup регулярно (например, ночным cron-job в CI, отдельно от обычного werf build/werf converge пайплайна разработки), т.к. очистка не блокирует и не требует остановки текущей разработки — это независимая фоновая операция обслуживания registry.

Как настроить политику под релизный цикл Application-пакета

Для Application-пакета курса типичная стратегия — комбинация: держать все семверные релизные теги (references.tag: /^v\d+\.\d+\.\d+$/ без ограничения limit, т.к. семверные релизы — это то, что реально устанавливают пользователи через d8 package build --version, разбирается в M5 уроке 9) и ограниченно — образы веток разработки (feature-ветки, main до релиза).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cleanup:
  keepPolicies:
    - references:
        tag: /^v\d+\.\d+\.\d+$/
        # без limit — хранить ВСЕ семверные релизы бессрочно
    - references:
        branch: /.*/
        limit:
          last: 5
          in: 336h
          operator: And
      imagesPerReference:
        last: 1

Частые ошибки и подводные камни

  • Не настраивать cleanup вообще и полагаться только на дефолт. Дефолтные политики — разумный старт, но не всегда соответствуют реальному релизному циклу конкретного Application-пакета — например, если релизные семверные теги должны храниться бессрочно, дефолтное limit.last: 10 для тегов рано или поздно удалит старые релизы, которые ещё используют пользователи.
  • Путать imagesPerReference (сколько образов на ссылку) с limit внутри references (сколько самих ссылок отбирается). Это два независимых измерения политики, легко перепутать при чтении конфигурации.
  • Запускать werf cleanup без понимания, что он анализирует текущую Git-историю. Если локальный клон/CI-раннер видит не все ветки/теги (например, shallow clone без всех веток), werf cleanup может неверно определить, что считается «активным», и удалить нужные образы.

Практика в кластере

Практики в кластере в этом уроке нет — фокус на управлении registry.

Практика разработки

🧩 Практика урока: Vikunja · лицензия AGPL-3.0
  1. Добавьте секцию cleanup в werf.yaml Vikunja с политикой, ориентированной на семверные релизы:
1
2
3
4
5
6
7
8
cleanup:
  keepPolicies:
    - references:
        tag: /^v\d+\.\d+\.\d+$/
    - references:
        branch: /^main$/
      imagesPerReference:
        last: 3
  1. Соберите и опубликуйте несколько тестовых тегов, чтобы накопить историю (в реальном registry, доступном вашему кластеру/локальному Docker registry):
1
2
git tag v0.1.0 && werf build --repo <your-registry>/vikunja
git tag v0.2.0 && werf build --repo <your-registry>/vikunja
  1. Запустите cleanup в режиме анализа (без реального удаления, если у вашей версии werf есть dry-run флаг — проверьте werf cleanup --help) и изучите, что будет удалено:
1
werf cleanup --repo <your-registry>/vikunja
  1. Изучите разницу между дефолтными keepPolicies (без явной секции cleanup в werf.yaml) и вашей кастомной политикой — какие образы попали бы под удаление в каждом случае.

Шпаргалка команд урока

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cleanup:
  keepPolicies:
    - references:
        tag: /<regex>/
        branch: /<regex>/
        limit:
          last: <N>
          in: <duration>
          operator: And|Or
      imagesPerReference:
        last: <N>
        in: <duration>
        operator: And|Or
1
2
werf cleanup --repo <registry-address>
werf cleanup --repo <registry-address> --keep-list=keep-list.txt

Вопросы для самопроверки

Как объединяются результаты нескольких keepPolicies?

Политики работают как объединение множеств сохраняемых образов — достаточно соответствия хотя бы одной.

Источник: Werf — документация — Default Cleanup Policies

Чем references отличается от imagesPerReference в политике cleanup?

Два независимых измерения: выбор ссылок (references) и количество образов на ссылку (imagesPerReference).

Источник: Werf — документация

Почему для Git-тегов не имеет смысла limit.last больше 1 внутри imagesPerReference?

В отличие от веток, которые двигаются вперёд, тег фиксирован на одном коммите — только HEAD-коммит тега проверяется.

Источник: Werf — документация

Что произойдёт с образом на активной ветке main, если формально он 'старый' по дате публикации, но main попадает в keepPolicies без ограничения по количеству веток?

werf cleanup сопоставляет реальную Git-историю (актуальные ветки/теги) с политиками — 'старость по дате' сама по себе не критерий удаления без контекста.

Источник: Werf — документация — механика на основе Git-истории

Какая стратегия рекомендуется для семверных релизных тегов Application-пакета?

Семверные релизные теги — то, что устанавливают через d8 package build --version; их удаление ломает возможность откатиться или переустановить старую версию.

Источник: Рекомендуемая литература

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Nigel Poulton. Docker Deep Dive. 2023. ISBN 978-1916585206.

Связанные материалы