О бандлах и чартах

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

Команда werf bundle publish собирает образы и публикует их вместе с чартом для дальнейшего развёртывания с werf. При этом для развёртывания доступ к Git-репозиторию приложения больше не потребуется.

Опубликованный чарт — обычный OCI-чарт Helm: исходный чарт как есть плюс директория .werf-data/ в его корне. В .werf-data/ хранится всё, что werf добавляет при публикации:

  • собранные образы и их теги в виде служебных параметров werf;
  • параметры, переданные опциями --values, --secret-values, --set*, --set-root-json, и файлы --patches;
  • пользовательские и служебные аннотации и лейблы для добавления в ресурсы чарта;
  • имя релиза и Namespace, вычисленные для окружения.

werf bundle apply (а также werf bundle plan и werf bundle render) использует всё это, поэтому публикация и последующее применение чарта развёртывают то же самое, что werf converge с теми же опциями. Helm, Argo CD, Flux и другие решения тоже могут установить чарт, но по умолчанию получают только собственные параметры чарта, см. Использование чарта с Helm, Argo CD и Flux.

Опубликованный бандл (чарт и связанные с ним образы) можно копировать в другой репозиторий container registry или выгружать в/из архива с помощью одной команды werf bundle copy.

Аутентификация в container registry

Перед работой с образами необходимо аутентифицироваться в container registry. Сделать это можно командой werf cr login:

werf cr login <registry url>

Например:

# Login with username and password from command line
werf cr login -u username -p password registry.example.com

# Login with token from command line
werf cr login -u username -p token registry.example.com

# Login into insecure registry (over http)
werf cr login --insecure-registry registry.example.com

В случае использования команды ci-env с поддерживаемыми CI/CD-системами аутентификация во встроенные container registry выполняется в рамках команды, поэтому использование команды werf cr login в этом случае не требуется.

Публикация бандла

Опубликовать бандл в OCI-репозиторий можно следующим способом:

  1. Создайте werf.yaml, если его ещё нет:

    # werf.yaml:
    project: mybundle
    configVersion: 1
    
  2. Разместите файлы в директории основного чарта (по умолчанию .helm в корне Git-репозитория). Публикуются все файлы директории чарта, кроме исключённых .helmignore (см. ниже).

  3. Следующей командой опубликуйте бандл. Соберите и опубликуйте описанные в werf.yaml образы (если таковые есть), затем опубликуйте содержимое .helm в виде чарта example.org/bundles/mybundle с тегом latest:

    werf bundle publish --repo example.org/bundles/mybundle
    

Содержимое опубликованного чарта

Директория чарта публикуется как есть: werf ничего не добавляет в values.yaml, а secret-values.yaml и директория secret/ чарта остаются на своих местах в зашифрованном виде. В Chart.yaml werf меняет только следующие поля, сохраняя остальное содержимое файла, включая комментарии и порядок ключей:

  • name — последний компонент пути репозитория (см. Имя и версия чарта);
  • version — версия, полученная из тега;
  • appVersion — только если она задана в werf.yaml;
  • аннотацию helm.sh/images — собранные werf образы и ссылки на них, добавленные к записям, которые указал автор чарта. Если имя записи автора совпадает с именем образа werf, публикация завершается ошибкой: удалите запись из Chart.yaml или переименуйте образ werf.

Также werf помещает в charts/ зависимые чарты, перечисленные в Chart.lock, и собирает TypeScript-чарты.

Всё, что werf добавляет при публикации, попадает в .werf-data/:

.werf-data/
  metadata.yaml        # версия формата (apiVersion: v2), опции --set*, образы werf, файлы --patches, аннотации, лейблы, имя релиза и Namespace
  values.yaml          # файлы --values, объединённые по порядку
  secret-values.yaml   # файлы --secret-values, объединённые по порядку, в зашифрованном виде
  extra-values.yaml    # служебные параметры werf: образы, репозиторий, окружение, коммит
  set-files/0, 1, ...  # содержимое файлов --set-file
  patches/0, 1, ...    # файлы --patches

.werf-data/ всегда публикуется и сохраняется при распаковке и повторной упаковке чарта, даже если её исключает .helmignore чарта.

Примечание: .werf-data/values.yaml, файлы set-files/ и строки --set* хранятся в registry в открытом виде. Передавайте секреты только через --secret-values: werf проверяет, что все значения в этих файлах зашифрованы, и хранит их в зашифрованном виде.

Публикация нескольких бандлов из одного Git-репозитория

Разместите .helm с содержимым чарта и соответствующий ему werf.yaml в отдельную директорию для каждого бандла:

bundle1/
  .helm/
    templates/
    # ...
  werf.yaml
bundle2/
  .helm/
    templates/
    # ...
  werf.yaml

Теперь опубликуйте каждый бандл по отдельности:

cd bundle1
werf bundle publish --repo example.org/bundles/bundle1

cd ../bundle2
werf bundle publish --repo example.org/bundles/bundle2

Исключение файлов или директорий из чарта

Файл .helmignore чарта фильтрует публикуемый чарт так же, как любой чарт, который читает werf, см. Исключение файлов или директорий из чарта.

Опции --disable-default-values, --disable-default-secret-values и --no-default-patches команды werf bundle publish сохраняются в чарте: werf bundle apply тогда игнорирует values.yaml, secret-values.yaml и patches.yaml чарта, как это делает werf converge с этими опциями. Сами файлы остаются в чарте, и Helm по-прежнему использует values.yaml.

Если в директории чарта уже есть .werf-data/ с этими переключателями, например закоммиченный распакованный опубликованный чарт, werf bundle publish сохраняет их: опция со значением true устанавливает сохранённый переключатель, а неуказанная опция или опция со значением false его сохраняет. Чтобы сбросить сохранённый переключатель, удалите defaultValuesDisable или defaultSecretValuesDisable в секции values или defaultPatchesDisable из файла .werf-data/metadata.yaml чарта.

Использование произвольных тегов образов

Для использования произвольных тегов образов для бандлов необходимо задать шаблон именования с помощью опции --use-custom-tag (WERF_USE_CUSTOM_TAG).

Пример использования:

werf bundle publish --repo example.org/bundles/mybundle --use-custom-tag "%image%-my-custom-tag"

werf bundle publish отказывается публиковать чарт, если тег его версии или тег, указанный в --tag, совпадает с тегом образа werf в том же репозитории, так как публикация чарта перезаписала бы образ. В этом случае опубликуйте бандл с другим --tag или используйте другой тег образа.

Подробнее про кастомные теги можно прочитать в документации.

Имя и версия чарта

Имя чарта — всегда последний компонент пути репозитория, в который публикуется чарт: werf bundle publish --repo example.org/bundles/mybundle публикует чарт mybundle. Helm находит OCI-чарт только в репозитории, названном по имени чарта.

По умолчанию чарт публикуется с тегом latest. Указать иной тег, например, семантическую версию, можно опцией --tag:

werf bundle publish --repo example.org/bundles/mybundle --tag v1.0.0

Версия чарта определяется по тегу:

  • строгая семантическая версия (MAJOR.MINOR.PATCH с необязательными prerelease и build, с необязательным префиксом v) используется как есть, без префикса v: v1.0.0 → 1.0.0;
  • любой другой тег (latest, SHA коммита, имя ветки, 1.2, число вроде даты или ID пайплайна) получает версию 0.0.0-<unix-время>-<slug тега>, где slug — тег в нижнем регистре, в котором каждая последовательность символов, кроме букв и цифр, заменена на -: feature_Foo_1 → 0.0.0-<unix-время>-feature-foo-1. Если версия получилась бы длиннее 128 символов, максимальной длины тега, slug обрезается и к нему добавляется - и первые 8 шестнадцатеричных цифр SHA-256 тега.

werf публикует чарт с тегом его версии и, если он отличается, ещё и с указанным тегом, заменяя в обоих + на _, как это делает Helm: --tag 1.0.0+build.5 публикует 1.0.0_build.5. Команда выше публикует example.org/bundles/mybundle:1.0.0 и example.org/bundles/mybundle:v1.0.0, оба указывают на один и тот же чарт.

Тег, оканчивающийся на .prov, недопустим, так как такие теги адресуют файлы provenance.

Версия 0.0.0-… — это prerelease, поэтому Helm, Argo CD и Flux пропускают её при выборе версии по semver-диапазону: чтобы её выбрать, используйте диапазон вида >=0.0.0-0 или опцию Helm --devel. Две публикации с не-semver тегом в пределах одной секунды получают одинаковую версию и перезаписывают друг друга. Такие версии накапливаются в registry: очистка werf их не удаляет.

Если при публикации будет обнаружено, что в OCI-репозитории уже существует чарт с таким тегом, то чарт в репозитории будет перезаписан.

Развёртывание бандла

werf bundle apply развёртывает опубликованный чарт без доступа к Git-репозиторию приложения:

werf bundle apply --repo example.org/bundles/mybundle --tag v1.0.0

werf bundle publish и последующий werf bundle apply развёртывают то же самое, что werf converge с опциями, переданными werf bundle publish, а werf release get --print-values показывает те же параметры. Опции, переданные werf bundle apply (--values, --secret-values, --set*, --set-root-json, --patches, --add-annotation, --add-label), применяются поверх сохранённых при публикации и имеют приоритет над ними. Параметры объединяются в следующем порядке, от низшего приоритета к высшему:

  1. values.yaml и secret-values.yaml чарта.
  2. Опции --values, --secret-values, --set* и --set-root-json команды werf bundle publish.
  3. Служебные параметры werf, вычисленные при публикации (образы, репозиторий, окружение, коммит).
  4. Опции --values, --secret-values, --set* и --set-root-json команды werf bundle apply.
  5. Служебные параметры werf, вычисленные при развёртывании (окружение, Namespace и другие).

Файлы --patches применяются в том же порядке: собственный patches.yaml чарта, затем файлы werf bundle publish, затем файлы werf bundle apply. Опции --disable-default-values и --disable-default-secret-values команды werf bundle apply игнорируют только values.yaml и secret-values.yaml чарта, но не параметры, сохранённые при публикации.

--secret-values команды werf bundle publish расшифровываются при развёртывании и сохраняются в релизе в расшифрованном виде, так же как werf converge сохраняет свои --secret-values, см. Секретные параметры в релизе. Для их расшифровки нужен секретный ключ, которым они были зашифрованы при публикации.

werf bundle publish сохраняет имя релиза и Namespace, вычисленные так же, как их вычисляет werf converge для указанного --env. werf bundle apply, werf bundle plan и werf bundle render используют их вместо непереданных --release и --namespace, в том числе когда не передан --env. Если вы передаёте непустой --env, отличный от использованного при публикации, сохранённые значения не используются и обязательны оба флага, --release и --namespace.

Единственное известное отличие от werf converge — .Chart.Name и .Chart.Version: при werf converge шаблоны получают имя проекта и версию из Chart.yaml (по умолчанию 1.0.0), а при werf bundle apply — имя репозитория и версию, полученную из тега. Поэтому лейбл вида helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} различается, и переход релиза с werf converge на werf bundle apply один раз перезапускает его Pod’ы.

werf converge, werf plan, werf render и werf lint тоже используют .werf-data/, если находят её в директории чарта (например, если в .helm лежит распакованный опубликованный чарт): её параметры, аннотации и лейблы применяются ниже опций команды.

Использование опубликованного чарта как зависимого

Когда werf или Nelm развёртывает чарт, который подключает опубликованный werf чарт как зависимый, параметры из .werf-data/ зависимого чарта становятся его параметрами по умолчанию, как если бы он развёртывался сам по себе с werf converge. Родительский чарт переопределяет их как обычно. Секретные параметры зависимого чарта расшифровываются секретным ключом развёртывания и, как параметры из secret-values.yaml любого зависимого чарта, сохраняются в релизе в расшифрованном виде. Его общие для релиза входные данные игнорируются с предупреждением, так как их определяет родительский чарт: аннотации и лейблы, --patches, --no-default-patches, --set-root-json, а также имя релиза и Namespace. werf bundle publish всегда сохраняет имя релиза и Namespace, поэтому развёртывание любого зависимого чарта, опубликованного werf, выводит это предупреждение.

Параметры global.*, включая global.werf.*, общие с родительским чартом, как и глобальные параметры в Helm: если родительский и зависимый чарт задают один и тот же ключ в global, зависимый чарт получает значение родительского. Параметры werf.* зависимого чарта остаются его собственными. Например, в шаблонах зависимого чарта, опубликованного с образом app:

image: {{ .Values.werf.image.app }}  # образ, опубликованный с зависимым чартом
repo: {{ .Values.global.werf.repo }}  # репозиторий werf-проекта родительского чарта

Изменение опубликованного чарта

Опубликованный чарт можно скачать, изменить и опубликовать снова без Git-репозитория приложения, например, с помощью CLI Nelm:

  1. Скачайте и распакуйте чарт:

    nelm chart download oci://example.org/bundles/mybundle --version 1.0.0 --untar
    
  2. Измените чарт: values.yaml, секреты (nelm chart secret values-file edit mybundle/secret-values.yaml или mybundle/.werf-data/secret-values.yaml), шаблоны или любой файл в .werf-data/.

  3. Упакуйте чарт и загрузите его:

    nelm chart pack mybundle --set replicas=3
    nelm chart upload mybundle-1.0.0.tgz oci://example.org/bundles
    

nelm chart pack сохраняет версию из Chart.yaml, если не передан --chart-version, и сохраняет архив в текущую директорию, если не передан --destination. Опции --values, --secret-values, --set*, --set-root-json и --patches команды nelm chart pack добавляются поверх сохранённых в .werf-data/, как если бы их дописали в конец исходной команды werf bundle publish: файлы параметров объединяются поверх сохранённых, а опции --set*, --set-root-json и --patches добавляются после сохранённых. Опции --no-default-values, --no-default-secret-values и --no-default-patches устанавливают сохранённые переключатели, но не сбрасывают их. Опция --reset-values удаляет всё сохранённое в .werf-data/ перед применением опций этой упаковки. Чтобы удалить одну сохранённую опцию, отредактируйте .werf-data/ и упакуйте чарт. При удалении сохранённого файла параметров (.werf-data/values.yaml, .werf-data/secret-values.yaml или .werf-data/extra-values.yaml) удалите и его флаг из секции values файла .werf-data/metadata.yaml (values: true, secretValues: true или extraValues: true), иначе упаковка и развёртывание чарта завершатся ошибкой вида .werf-data/metadata.yaml: values: true does not match the presence of values.yaml. Секретный ключ для nelm chart pack не нужен.

TypeScript-чарт при упаковке пересобирается, для чего нужен доступ к сети для скачивания его модулей. Чтобы вместо этого использовать собранный TypeScript-код скачанного чарта, передайте --ts-no-rebuild.

Чарт, опубликованный werf 3.12 и более ранними версиями, тоже можно переупаковать: nelm chart pack переносит его extra_annotations.json и extra_labels.json в .werf-data/, а его values.yaml, содержащий объединённые при публикации параметры, остаётся собственным values.yaml чарта.

Вместо nelm chart pack и nelm chart upload можно использовать helm package и helm push: они сохраняют .werf-data/, если её не исключает .helmignore чарта.

Изменение версии опубликованного чарта

Для изменения тега уже опубликованного чарта скопируйте бандл с новым тегом с помощью команды werf bundle copy, например:

werf bundle copy --from example.org/bundles/mybundle:v1.0.0 --to example.org/bundles/renamedbundle:v2.0.0

werf bundle copy --to REPO:TAG задаёт версию копии по TAG по тем же правилам, что и werf bundle publish, и публикует копию с тегом версии и указанным тегом. werf bundle copy --to REPO без тега сохраняет версию и тег исходного чарта. Копия называется по последнему компоненту пути целевого репозитория.

Копирование бандла в другой репозиторий

Для удобного копирования бандла в другой репозиторий имеется команда werf bundle copy. Кроме непосредственного копирования чарта и связанных с ним образов эта команда также заново формирует ссылки на образы в .werf-data/extra-values.yaml и в аннотации helm.sh/images для целевого репозитория.

Пример:

werf bundle copy --from example.org/bundles/mybundle:v1.0.0 --to other.example.org/bundles/mybundle:v1.0.0

Образы копируются по digest, мультиплатформенные образы — со всеми платформами. Образы чартов с .werf-data/, подключённых как зависимые на любом уровне вложенности, тоже копируются, а их аннотации helm.sh/images и .werf-data/extra-values.yaml переписываются для целевого репозитория. У бандла, опубликованного werf 3.12 или более ранней версией и подключённого как зависимый, нет .werf-data/: его образы не копируются, а значения не переписываются.

У бандла, опубликованного werf 3.12 или более ранней версией, нет .werf-data/: его образы берутся из значений werf.image, а значения werf.image, werf.repo и global.werf в его values.yaml переписываются для целевого репозитория.

Подписанный чарт (с provenance-файлом Helm) сохраняет подпись при копировании без изменений. Если при копировании чарт меняется, например, переписываются ссылки на образы, меняется имя или версия, подпись удаляется с предупреждением.

werf bundle apply, werf bundle plan и werf bundle render проверяют подпись бандла, скачанного из container registry, по публичным ключам из --provenance-keyring, если передан --provenance-strategy=verify (бандл без подписи вызывает ошибку) или --provenance-strategy=verify-if-possible (проверяется только подписанный бандл). werf bundle render --bundle-dir не может проверить подпись распакованного бандла и с --provenance-strategy=verify завершается ошибкой.

Экспорт бандла из container registry в архив

После публикации бандл может быть экспортирован из репозитория в локальный архив для дальнейшей дистрибуции иными способами с помощью команды werf bundle copy, например:

werf bundle copy --from example.org/bundles/mybundle:v1.0.0 --to archive:archive.tar.gz

Архив — это tar-файл, сжатый gzip, если его имя заканчивается на .gz или .tgz, с OCI image layout внутри (oci-layout, index.json, blobs/sha256/…). В нём хранятся чарт, вместе с provenance-файлом, если чарт подписан, и все образы чарта по digest:

  • мультиплатформенные образы сохраняются со всеми платформами;
  • non-distributable (foreign) слои образов тоже копируются в архив;
  • referrers образов, например подписи и SBOM, привязанные к ним, не копируются.

werf 3.12 и более ранние версии не могут прочитать такие архивы: импортируйте их текущей версией werf.

Импорт бандла из архива в репозиторий

Экспортированный в архив бандл можно снова импортировать в тот же или другой OCI-репозиторий командой werf bundle copy, например:

werf bundle copy --from archive:archive.tar.gz --to other.example.org/bundles/mybundle:v1.0.0

После этого вновь опубликованный бандл (чарт и его образы) снова можно использовать привычными способами.

Архивы, созданные werf 3.12 и более ранними версиями (с chart.tar.gz и images/*.tar.gz внутри), по-прежнему можно импортировать. У них нет тега, поэтому без тега в --to бандл публикуется только под версией чарта.

Использование чарта с Helm, Argo CD и Flux

Helm, Argo CD и Flux устанавливают опубликованный чарт с его собственным values.yaml и параметрами, переданными им при установке. Сами они не читают .werf-data/, поэтому ссылок на образы и параметров, переданных werf bundle publish, у них нет: шаблоны, использующие .Values.werf.image.* или .Values.global.werf.images.*, получают пустые ссылки.

Примечание: в чартах, опубликованных werf 3.12 и более ранними версиями, ссылки на образы и опции --values и --set* команды werf bundle publish объединялись в values.yaml. В новых чартах этого нет, поэтому для развёртывания нового чарта через Helm, Argo CD или Flux нужны файлы параметров, описанные ниже.

.werf-data/values.yaml (--values команды werf bundle publish) и .werf-data/extra-values.yaml (ссылки на образы и другие служебные параметры werf) — обычные YAML-файлы внутри чарта, поэтому их можно передать как файлы параметров. werf bundle publish всегда создаёт .werf-data/extra-values.yaml, а .werf-data/values.yaml — только если получает --values: либо перечислите только те файлы, которые есть в чарте, либо разрешите Flux и Argo CD пропускать отсутствующие файлы, как показано ниже.

Flux, HelmRelease, чарт которого берётся из HelmRepository типа oci:

spec:
  chart:
    spec:
      chart: mybundle
      sourceRef:
        kind: HelmRepository
        name: bundles
      valuesFiles:
        - values.yaml
        - .werf-data/values.yaml
        - .werf-data/extra-values.yaml
      ignoreMissingValuesFiles: true

valuesFiles заменяет список файлов параметров по умолчанию, поэтому values.yaml нужно указать первым.

Argo CD, пути указываются относительно корня чарта:

spec:
  source:
    repoURL: example.org/bundles
    chart: mybundle
    targetRevision: 1.0.0
    helm:
      valueFiles:
        - .werf-data/values.yaml
        - .werf-data/extra-values.yaml
      ignoreMissingValueFiles: true

Argo CD скачивает чарт из container registry, только если репозиторий (example.org/bundles) зарегистрирован в Argo CD как Helm-репозиторий с enableOCI: "true", например, в Secret репозитория с type: helm.

Даже с этими файлами параметров в Helm, Argo CD и Flux недоступно следующее:

  • опции --set* команды werf bundle publish;
  • секреты: Helm не может расшифровать secret-values.yaml, .werf-data/secret-values.yaml и файлы secret/, а шаблоны, вызывающие werf_secret_file, завершаются ошибкой;
  • аннотации и лейблы werf bundle publish;
  • --disable-default-values команды werf bundle publish: Helm по-прежнему использует values.yaml чарта;
  • ресурсы, генерируемые TypeScript: Helm не выполняет ts/;
  • всё из .werf-data/, если опубликованный werf чарт — зависимый чарт чарта, развёртываемого через Helm, Argo CD или Flux.

Helm помещает .werf-data/ в .Files и сохраняет её в релизе вместе с остальным чартом (.werf-data/secret-values.yaml остаётся зашифрованным). Шаблоны, читающие все файлы чарта, например через .Files.Glob "**", получают и файлы .werf-data/.

Совместимость с другими версиями werf и Nelm

Чарты, опубликованные werf 3.12 и более ранними версиями, текущая версия werf развёртывает без изменений.

Текущий формат чарта (apiVersion: v2 в .werf-data/metadata.yaml) требует werf v3 или Nelm v2 с поддержкой .werf-data/. Релизы werf v2 и Nelm v1, включающие проверку (werf/werf#8141, werf/nelm#808), отказываются развёртывать такой чарт, а также чарт, подключающий его как зависимый. Релизы werf v2 и Nelm v1 без этой проверки, werf 3.12 и более ранние версии, а также версии Nelm v2 без поддержки .werf-data/ не отказываются: они развёртывают чарт только с его собственными параметрами, без ссылок на образы, параметров, секретов, аннотаций и лейблов werf bundle publish.

Container registries, поддерживающие публикацию бандлов

Для публикации бандлов требуется container registry, поддерживающий спецификацию OCI (Open Container Initiative). Список наиболее популярных container registries, совместимость с которыми была проверена:

Container registry Поддерживает публикацию бандлов
AWS ECR +
Azure CR +
Docker Hub +
GCR +
GitHub Packages +
GitLab Registry +
Harbor +
JFrog Artifactory +
Yandex container registry +
Nexus +
Quay -