Поддержка monorep и multirep в werf и при чём здесь Docker Registry

g5ty-1te67utdbhfehomgnaorv8.png

Тема монорепозитория обсуждалась уже не раз и, как правило, вызывает весьма активные споры. Создавая werf как Open Source-инструмент, призванный улучшить процессы сборки кода приложений из Git в Docker-образы (и их последующей доставки в Kubernetes), мы мало размышляем на тему того, какой выбор лучше. Для нас первично обеспечить всё необходимое для сторонников разных мнений (если это не противоречит здравому смыслу, конечно).

Появившаяся недавно поддержка monorep в werf — хороший тому пример. Но для начала давайте разберёмся, как эта поддержка вообще связана с использованием werf и при чём здесь Docker Registry…

Проблематика


Представим такую ситуацию. В компании имеется множество команд разработчиков, занимающихся независимыми проектами. Большинство приложений функционируют в Kubernetes, а соответственно — контейнезируются. Для хранения контейнеров, образов, необходим реестр (registry). В качестве такого реестра в компании используется Docker Hub с единственным аккаунтом COMPANY. По аналогии с большинством систем хранения исходного кода, Docker Hub не позволяет создавать вложенную иерархию репозиториев, такую как COMPANY/PROJECT/IMAGE. В таком случае… как же с этим ограничением хранить в реестре немонолитные приложения, не создавая отдельный аккаунт под каждый проект?

1bhsfo_ra_iwvlnwtsywb201l5w.png

Возможно, описанная ситуация кому-то не понаслышке знакома, но давайте рассмотрим вопрос организации хранения приложений в общем, т.е. без привязки к вышеописанному примеру и Docker Hub.

Пути решения


Если приложение монолитно, поставляется в одном образе, то вопросов не возникает и мы просто сохраняем образы в реестр контейнеров проекта.

Когда приложение представлено в виде нескольких компонентов, микросервисов, то требуется выбрать определённый подход. На примере типового web-приложения, состоящего из двух образов: frontend и backend — возможные варианты таковы:

  1. Хранить образы в отдельных вложенных репозиториях:

    nv2fj3mhvd2nfn-llrd8n6va2v4.png

  2. Хранить всё в одном репозитории, а имя образа учитывать в теге, к примеру, следующим образом:

    hv9myms2iq6sh354wrnp7ni4jfy.png


NB: Вообще-то, есть ещё вариант с сохранением в различных репозиториях, PROJECT-frontend и PROJECT-backend, но его мы не будем рассматривать из-за сложности поддержки, организации и распределения прав между пользователями.

Поддержка в werf


Изначально werf ограничился вложенными репозиториями — благо, большинство реестров поддерживают такую возможность. Начиная с версии v1.0.4-alpha.3, добавлена работа с реестрами, в которых не поддерживается вложенность, и Docker Hub — в их числе. С этого момента у пользователя появился выбор, как хранить образы приложения.

Реализация доступна в рамках опции --images-repo-mode=multirep|monorep (по умолчанию multirep, т.е. хранение во вложенных репозиториях). Она определяет шаблоны, по которым образы хранятся в реестре. Достаточно выбрать нужный режим при использовании основных команд, а всё остальное останется неизменным.

Поскольку большинство опций werf можно задавать переменными окружения, в CI/CD-системах режим хранения, как правило, легко задать глобально для всего проекта. Например, в случае с GitLab достаточно добавить переменную окружения в настройках проекта: Settings → CI / CD → Variables: WERF_IMAGES_REPO_MODE: multirep|monorep.

Если говорить о публикации образов и выкате приложений (об этих процессах можно подробно прочитать в соответствующих статьях документации: Publish process и Deploy process), то режим исключительно определяет шаблон, по которому можно работать с образом.

Дьявол в деталях


Отличие и основная сложность при добавлении нового способа хранения — в процессе очистки registry (возможности чистки, поддерживаемые в werf, см. в Cleaning process).

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

  1. 3 стратегии, связанные Git-примитивами, такими как тег, ветка и коммит;
  2. 1 стратегия для произвольных пользовательских тегов.


Информацию о стратегии тега мы сохраняем при публикации образа в лейблах конечного образа. Само значение — так называемый метатег — необходим для применения части политик. Например, при удалении ветки или тега из Git-репозитория логично удалять и связанные неиспользуемые образы из реестра, что и покрывается частью наших политик.

При сохранении в одном репозитории (monorep), в теге образа, помимо метатега также может храниться имя образа: PROJECT:frontend-META-TAG. Для их разделения мы не стали вводить какой-то специфичный разделитель, а просто добавили необходимое значение в лейбл конечного образа при публикации.

NB: Если интересно посмотреть на всё описанное в исходном коде werf, то отправной точкой может служить PR 1684.

В этой статье мы не будем уделять больше внимания проблематике и обоснованию нашего подхода: про стратегии тегирования, хранения данных в лейблах и процесс публикации в целом —обо всём этом подробно рассказано в недавнем докладе Дмитрия Столярова: «werf — наш инструмент для CI/CD в Kubernetes».

Резюмируя


Отсутствие поддержки реестров без вложенности не являлось блокирующим фактором для нас или известных нам пользователей werf — ведь всегда можно поднять отдельный реестр образов (или перейти на условный Container Registry в Google Cloud)… Однако снятие такого ограничения выглядело логичным для того, чтобы инструмент был удобен более широкому DevOps-сообществу. Реализуя его, мы столкнулись с главной сложностью в переработке механизма очистки реестра контейнеров. Теперь, когда всё готово, приятно осознавать, что кому-то стало легче, а у нас (как главных разработчиков проекта) заметных сложностей в дальнейшей поддержке этой фичи не предвидится.

Оставайтесь с нами и совсем скоро мы расскажем о других нововведениях в werf!

P.S.


Читайте также в нашем блоге:

© Habrahabr.ru