Процедура публикации образа

Процесс публикации образа при обычной работе с Docker, состоит из следующих этапов:

docker tag REPO:TAG
docker push REPO:TAG
docker rmi REPO:TAG
  1. Получение имени или id собранного локального образа.
  2. Создание временного образа-псевдонима, состоящего из следующих частей:
  3. Публикация образа-псевдонима в Docker registry.
  4. Удаление временного образа-псевдонима.

В werf реализована иная логика публикации образа, описанного в конфигурации:

  1. Создание нового образа с определенным именем на основе соответствующего собранного образа. В созданном образе хранится информация о применяемой схеме тегирования, необходимая для внутреннего использования werf (эта информация сохраняется с использованием docker labels). Далее, такая информация будет упоминаться как мета-информация образа. werf использует мета-информацию образа в процессе деплоя и процессе очистки.
  2. Публикация созданного образа в Docker registry.
  3. Удаление образа, созданного на этапе 1.

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

Результатом процесса публикации образа является образ, именованный согласно правил именования образов и загруженный в Docker registry. Все эти шаги выполняются с помощью команды werf publish или werf build-and-publish.

Именование образов

Во время процесса публикации образа, werf формирует имя образа используя:

  • значение параметра --images-repo;
  • значение параметра --images-repo-mode;
  • имя образа из файла конфигурации werf.yaml;
  • значение параметра тегирования.

Итоговое имя Docker-образа имеет формат — DOCKER_REPOSITORY:TAG.

Параметры --images-repo и --images-repo-mode определяют адрес хранения образов и формат его имени в репозитории. Если в конфигурации проекта (файл werf.yaml) описан только один безымянный образ, то значение параметра --images-repo используется в качестве имени Docker-репозитория без изменений. Имя Docker-образа в таком случае будет соответствовать шаблону: IMAGES_REPO:TAG.

Если в конфигурации проекта (файл werf.yaml) описано несколько образов, то шаблон имени Docker-образа будет зависеть от значения параметра --images-repo-mode:

  • IMAGES_REPO:IMAGE_NAME-TAG в случае значения monorepo для параметра --images-repo-mode;
  • IMAGES_REPO/IMAGE_NAME:TAG в случае значения multirepo для параметра --images-repo-mode (используется по умолчанию).

Большинство реализаций Docker registry позволяют создавать иерархию репозиториев, например, COMPANY/PROJECT/IMAGE. В этом случае вам нет необходимости менять значение парамера --images-repo-mode со значения по умолчанию — multirepo. Но, если у вас в проекте описано несколько образов, и вы работаете с Docker registry неподдерживающим иерархию репозиториев (самый яркий пример, это — Docker Hub), то вам потребуется указать значение monorepo в параметре --images-repo-mode. Подробнее о работе режима monorepo/multirepo можно прочитать в нашей статье.

Значение, указываемое для параметра --images-repo может быть также передано через переменную окружения $WERF_IMAGES_REPO.

Значение, указываемое для параметра --images-repo-mode может быть также передано через переменную окружения $WERF_IMAGES_REPO_MODE. Пользователь может использовать различные Docker registry имплементации и некоторые из них имеют ограничения и различные значения по умолчанию для images repo (подробнее о работе с различными Docker registry имплементациями и их особенностях).

Именование образов должно быть одинаковым при выполнении команд publish, build-and-publish, deploy, а также команд процесса очистки. В противном случае вы можете получить не работающий pipeline и потерю образов и стадий по результатам работы очистки

Docker-тег определяется исходя из используемых параметров --tag-*:

option description
--tag-git-tag TAG Используется стратегия тегирования git-tag, — тегирование осуществляется по указанному git-тегу
--tag-git-branch BRANCH Используется стратегия тегирования git-branch, — тегирование осуществляется по указанной git-ветке
--tag-git-commit COMMIT Используется стратегия тегирования git-commit, — тегирование осуществляется по указанному хэшу git-коммита
--tag-custom TAG Тегирование осуществляется по указанному произвольному тегу
--tag-by-stages-signature Тегирование каждого образа по сигнатуре стадий этого образа

Все передаваемые параметры тегирования валидируются, с учетом стандартных ограничений Docker на содержание имени тега образа. При необходимости, вы можете использовать слагификацию (slug, slugify — преобразование текста к виду, удобному для восприятия человеком) тегов, читай подробнее об этом в соответствующей статье.

Используя параметры --tag-*, вы не просто указываете тег, которым нужно протегировать образ, а также определяете стратегию тегирования. Стратегия тегирования влияет на операцию очистки. В частности, политика очистки выбирается в зависимости от стратегии тегирования, а в случае использования стратегии тегирования по произвольному тегу политика очистки не применяется совсем.

Использование параметров тегирования --tag-git-* подразумевает указание аргументов в виде значений тегов, веток и коммитов git. Все такие параметры разработаны с учетом совместимости с современными CI/CD системами, в которых выполнение задания pipeline CI происходит в отдельном экземпляре git-дерева для конкретного git-коммита, а имена тега, ветки и хэш коммита передаются через переменные окружения (например, для GitLab CI это CI_COMMIT_TAG, CI_COMMIT_REF_NAME и CI_COMMIT_SHA).

Опция --tag-by-stages-signature=true включает метод тегирования образов по их содержимому.

Тегирование по содержимому образа

Werf v1.1 поддерживание тегирование по содержимому образов. Теги результирующих docker-образов зависят от содержимого этих образов.

При использовании команды werf publish --tag-by-stages-signature или werf ci-env --tagging-strategy=stages-signature werf будет тегировать образы по так называемой сигнатуре стадий образа. Каждый образ тегируется своей такой сигнатурой, которая рассчитывается по тем же правилам, что и сигнатуры отдельных стадий образа.

Сигнатура стадий образа зависит от его содержимого и также зависит от истории правок в git репозитории, которые привели к такому содержимому.

В целом в таких системах контроля версий как git бывают холостые коммиты в репозиторий, которые не должны менять результирующий образ. Например, это могут быть пустые коммиты, merge-коммиты или коммиты, изменяющие файлы, которые не попадают в результирующий образ.

При тегировании образов например по git-коммитам эти холостые коммиты будут заставлять werf создавать новые имена образов, даже если содержимое этих образов не поменялось. А новые имена образов в свою очередь вызовут перезапуски Pod’ов приложения в Kubernetes, что уже является совсем нежелательным эффектом. В целом данный момент препятствует хранению множества сервисов в едином git репозитории.

Сигнатура стадий же напротив не будет меняться при создании таких холостых коммитов, и не будет вызывать перезапуски Pod’ов приложения в Kubernetes, при этом она как и commit-id остается связана с историей правок в git и отражает содержимое файлов.

Также можно сказать, что тегирование по сигнатуре стадий является более надежным методом тегирования, нежели тегирование по git-веткам, потому что содержимое результирующего образа не зависит от порядка запуска и выполнения задач в CI/CD системе. Сигнатура стадий приводит к стабильным неизменяемым образам, имя которых является адресом определенного содержимого этих образов.

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

Stages-signature — это стратегия тегирования образов по умолчанию в werf и является единственным рекомендуемым выбором. Стратегии тегирования также объясняются в статьях про интеграцию werf в CI/CD системы.

Объединение параметров

Любые параметры тегирования могут использоваться одновременно в любом порядке при выполнении команды werf publish или werf build-and-publish. В случае передачи нескольких параметров тегирования, werf создает отдельный образ на каждый переданный параметр тегирования, согласно каждому описанному в конфигурации проекта образу.

Примеры

Тегирование образов по содержимому

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend.

Выполнение команды:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-by-stages-signature

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6

где 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d — это сигнатура стадий образа backend и f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 — это сигнатура стадий образа frontend.

Эти теги зависят от содержимого образа и от истории правок в git, которые к этому содержимому привели. Каждая из этих сигнатур будет менятся при создании новых образов, поэтомe пользователь должен корректно обновлять манифесты конфигурации Kubernetes.

Два образа для одного git-тега

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend.

Выполнение команды:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-git-tag v1.2.0

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:v1.2.0
  • registry.hello.com/web/core/system/frontend:v1.2.0

Два образа для git-ветки

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend.

Выполнение команды:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-git-branch my-feature-x

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:my-feature-x;
  • registry.hello.com/web/core/system/frontend:my-feature-x.

Два образа для git-ветки, в названии которой есть специальные символы

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend.

Выполнение команды:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-git-branch $(werf slugify --format docker-tag "Features/MyFeature#169")

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:features-myfeature169-3167bc8c;
  • registry.hello.com/web/core/system/frontend:features-myfeature169-3167bc8c.

Обратите внимание, что команда werf slugify генерирует значение, допустимое для использования в качестве Docker-тега. Читайте подробнее про команду slug в соответствующем разделе.

Тегирование образов по содержимому в GitLab CI

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend. Имеем проект web/core/system в GitLab, и сконфигурированный Docker registry для проекта — registry.hello.com/web/core/system.

Запуск следующей команды в задании pipeline GitLab CI (для любой git-ветки или тега — не важно):

type werf && source $(werf ci-env gitlab --verbose --as-file)
werf publish --stages-storage :local

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d;
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6.

где 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d — это сигнатура стадий образа backend и f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 — это сигнатура стадий образа frontend.

Опция --tagging-strategy=stages-signature не была указана, потому что она используется по умолчанию.

Эти теги зависят от содержимого образа и от истории правок в git, которые к этому содержимому привели. Каждая из этих сигнатур будет менятся при создании новых образов, поэтому пользователь должен корректно обновлять манифесты конфигурации Kubernetes.

Два образа в задании GitLab CI

Имеем файл конфигурации werf.yaml с описанными двумя образами — backend и frontend. Имеем проект web/core/system в GitLab, и сконфигурированный Docker registry для проекта — registry.hello.com/web/core/system.

Запуск следующей команды в задании pipeline GitLab CI для ветки core/feature/ADD_SETTINGS:

type werf && source $(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose --as-file)
werf publish --stages-storage :local

приведет к созданию следующих образов соответственно:

  • registry.hello.com/web/core/system/backend:core-feature-add-settings-df80fdc3;
  • registry.hello.com/web/core/system/frontend:core-feature-add-settings-df80fdc3.

Обратите внимание, что werf автоматически применяет слагификацию к Docker-тегу core/feature/ADD_SETTINGS, — он будет конвертирован в тег core-feature-add-settings-df80fdc3. Эта конвертация выполняется при вызове команды werf ci-env, которая определяет название ветки из переменных окружения задания GitLab CI, слагифицирует его и заносит результат в переменную окружения WERF_TAG_GIT_BRANCH (альтернативный путь установки значения параметра --tag-git-branch). Читайте подробнее про команду slug в соответствующем разделе.

Безымянный образ в задании GitLab CI

Имеем файл конфигурации werf.yaml с описанным безымянным образом. Имеем проект web/core/queue в GitLab, и сконфигурированный Docker registry для проекта — registry.hello.com/web/core/queue.

Запуск следующей команды в задании pipeline GitLab CI для тега v2.3.1:

type werf && source $(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose --as-file)
werf publish --stages-storage :local

приведет к созданию образа registry.hello.com/web/core/queue:v2.3.1.