Сначала проверьте совместимость с v2, затем изменения сборки, деплоя и очистки registry. Удалённые возможности требуют изменений до обновления; устаревшие ключи пока работают с предупреждением.

Совместимость с v2

Для параллельной работы и отката на v2 важны не только версии бинарей, но и общие конфигурация, секреты и registry:

  • Конфигурация. После перехода на настройки v3 не рассчитывайте, что тот же werf.yaml будет работать в v2. Для отката сохраните совместимую с v2 ревизию конфигурации — см. изменения сборки.
  • Секреты. Старые секреты читаются в v3, но новые записи v3 не читаются старым клиентом. Обновите всех читателей до первой перезаписи; замена бинаря обратно на v2 не вернёт прежний формат — см. зашифрованные секреты.
  • Registry. Общий --repo означает общие образы, даже при отдельном --meta-repo. До переноса метаданных остановите старые задания, а образы для отката защитите от очистки. После переноса не возвращайте cleanup v2 на этот репозиторий — см. очистку registry.

Сборка

После перехода на v3 ожидайте полную пересборку образов. Учтите её при планировании обновления.

Образы вместо artifacts

Директива artifact удалена. Замените её на image с final: false:

Было — v2Стало — v3
artifact: builder
from: ubuntu:22.04
image: builder
from: ubuntu:22.04
final: false

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

Безымянные stapel-образы (image: ~) больше не поддерживаются — задайте каждому образу имя.

Имена теперь проверяются при загрузке конфигурации. Допустимы латинские буквы, цифры, _, ., - и +, а также сегменты через /. Каждый сегмент должен начинаться с буквы или цифры и заканчиваться буквой, цифрой или +. Имя modules/controller допустимо; пустое имя, пробелы, /api, api- и modules//controller вызывают ошибку конфигурации. Проверьте также имена, формируемые Go-шаблонами.

Единый from для ссылок на образы

Базовые образы и imports используют from и для внутренних, и для внешних образов. Имя образа из werf.yaml, например base, обозначает внутренний образ; ссылка с тегом или digest, например alpine:3.20, — внешний.

Ниже каждый блок — самостоятельный werf.yaml. Все образы, на которые ссылается конфигурация, объявлены в том же примере.

Базовый образ stapel

Образ app наследует образ base, объявленный выше. Замените fromImage: base на from: base:

Было — v2Стало — v3
configVersion: 1
project: migration-base
---
image: base
from: alpine:3.20
shell:
  install:
    - echo base > /base-marker
---
image: app
fromImage: base
shell:
  setup:
    - cat /base-marker
configVersion: 1
project: migration-base
---
image: base
from: alpine:3.20
shell:
  install:
    - echo base > /base-marker
---
image: app
from: base
shell:
  setup:
    - cat /base-marker

Импорт файлов из другого образа

Образ builder создаёт файл, а app копирует его до стадии setup. Замените import.image на import.from; также удалите stage, поскольку в v3 импортируется готовый образ-источник:

Было — v2Стало — v3
configVersion: 1
project: migration-import
---
image: builder
from: alpine:3.20
shell:
  setup:
    - mkdir -p /out
    - echo hello > /out/message.txt
---
image: app
from: alpine:3.20
import:
  - image: builder
    stage: setup
    add: /out/message.txt
    to: /message.txt
    before: setup
shell:
  setup:
    - cat /message.txt
configVersion: 1
project: migration-import
---
image: builder
from: alpine:3.20
shell:
  setup:
    - mkdir -p /out
    - echo hello > /out/message.txt
---
image: app
from: alpine:3.20
import:
  - from: builder
    add: /out/message.txt
    to: /message.txt
    before: setup
shell:
  setup:
    - cat /message.txt

Зависимость от образа

Образ app получает имя собранного образа backend в переменную BACKEND_IMAGE. Замените dependencies.image на dependencies.from; вложенный блок imports передаёт информацию об образе, а не копирует файлы:

Было — v2Стало — v3
configVersion: 1
project: migration-dependencies
---
image: backend
from: alpine:3.20
---
image: app
from: alpine:3.20
dependencies:
  - image: backend
    before: setup
    imports:
      - type: ImageName
        targetEnv: BACKEND_IMAGE
shell:
  setup:
    - echo "$BACKEND_IMAGE" > /backend-image.txt
configVersion: 1
project: migration-dependencies
---
image: backend
from: alpine:3.20
---
image: app
from: alpine:3.20
dependencies:
  - from: backend
    before: setup
    imports:
      - type: ImageName
        targetEnv: BACKEND_IMAGE
shell:
  setup:
    - echo "$BACKEND_IMAGE" > /backend-image.txt

Ключи fromImage, import.image и dependencies.image по-прежнему работают в v3, но выводят предупреждение об устаревании. Указание одновременно старого и нового ключа — ошибка. В отличие от этих ключей, import.stage удалён.

Внешний образ с явным тегом

Внешняя ссылка в базовом from или import.from требует явного тега или digest. Например, замените неявное :latest на явное:

Было — v2Стало — v3
configVersion: 1
project: migration-external
---
image: app
from: ubuntu
configVersion: 1
project: migration-external
---
image: app
from: ubuntu:latest

Вместо :latest можно указать нужный тег (:TAG) или digest (@sha256:...). Внутренним именам образов из werf.yaml тег не нужен.

Билдеры и настройки образа

Ansible-билдер удалён. Перепишите шаги ansible: с использованием Shell-билдера; переименования ключа недостаточно.

Директива docker: удалена. Перенесите настройки в imageSpec.config, преобразовав имена и форматы полей. Например, для фрагмента stapel-образа:

Было — v2Стало — v3
docker:
  WORKDIR: /app
  ENV:
    APP_ENV: production
imageSpec:
  config:
    workingDir: /app
    env:
      APP_ENV: production

Полный набор полей описан в разделе Изменение конфигурации образов.

Импорт файлов

Кеш импорта теперь зависит от образа-источника, а не от контрольных сумм выбранных файлов, как было по умолчанию в v2. Изменение источника может вызвать пересборку образа-получателя, даже если копируемые файлы не изменились. includePaths/excludePaths по-прежнему выбирают файлы для копирования, но больше не изолируют кеш от остальных изменений источника. Если такие пересборки дороги, выделите импортируемый результат в отдельный небольшой образ.

import.stage удалён. Импорт использует готовый образ-источник, а не выбранную промежуточную стадию. Если нужно промежуточное состояние, оформите его отдельным образом. before/after по-прежнему задают момент импорта в образе-получателе.

Завершающий / в to: директив export/import теперь вызывает ошибку, кроме корневого пути to: /. Раньше werf убирал его с предупреждением, хотя пользователь мог ожидать копирование «внутрь каталога». Перед заменой to: /usr/sbin/ на to: /usr/sbin проверьте назначение:

  • Если add — каталог, его содержимое сливается в to.
  • Если add — файл, он копируется внутрь to, когда to — существующий каталог; иначе to — путь файла назначения. Чтобы результат не зависел от наличия родительского каталога, укажите полное имя файла, например to: /etc/app/config.yaml, и убедитесь, что по этому пути нет каталога.

Подробнее — правила пути назначения.

Зависимости стадий от Git

git.stageDependencies определяет, какие изменения файлов Git запускают пересборку стадий. В v3 отсутствие настройки и явный пустой список могут иметь разный смысл:

Настройка Было — v2 Стало — v3
Весь блок отсутствует или задан как {} Прямой зависимости стадий от файлов Git нет. Все три стадии получают **/*: учитываются все файлы git mapping с его фильтрами includePaths/excludePaths.
Маски стадии заданы явно Учитываются подходящие файлы. То же поведение.
Для стадии явно задано [] Прямой зависимости от файлов Git нет. То же поведение; стадия считается явно объявленной.

В частично заполненном блоке пропущенные стадии до последней явно объявленной получают [], а после неё — **/*. Порядок всегда install → beforeSetup → setup, независимо от порядка ключей YAML. Правило применяется отдельно для каждого git mapping. В v2 любая пропущенная стадия не зависела от файлов Git, независимо от позиции: новые **/* после последней объявленной стадии могут добавить пересборки.

Например, задан только beforeSetup:

git:
  - add: /
    to: /app
    stageDependencies:
      beforeSetup:
        - "src/**/*"

install получает [], beforeSetup — src/**/*, setup — **/*. Поэтому изменение файла вне src само по себе не запускает install или beforeSetup, но запускает setup, если у неё есть инструкции.

Если заданы install и setup:

git:
  - add: /
    to: /app
    stageDependencies:
      install:
        - package-lock.json
      setup:
        - "src/**/*"

Пропущенный beforeSetup получает []: он находится до последней объявленной стадии setup. Пустой список тоже задаёт эту границу: при единственном beforeSetup: [] маски install и beforeSetup пусты, а setup получает **/*.

По умолчанию безопаснее: без настройки зависимостей изменения исходников запускают команды сборки заново. Сборки могут стать чаще. Чтобы сохранить отсутствие прямой Git-зависимости, задайте [] явно; чтобы стадия всегда учитывала все файлы mapping — ["**/*"]. Если задаёте маски, включите все файлы, влияющие на результат стадии.

[] отключает только прямую зависимость от файлов Git. Изменения предыдущих стадий, базового образа, команд и остальных входных данных по-прежнему могут вызвать пересборку. Маски не создают стадии без инструкций; beforeInstall в этот механизм не входит.

Непустой stageDependencies для стадии без инструкций сборки теперь вызывает ошибку вместо предупреждения. Например, этот фрагмент не пройдёт проверку при сборке:

git:
  - add: /
    to: /app
    stageDependencies:
      install:
        - "src/**/*"
shell:
  setup:
    - cd /app && sh src/build.sh

Зависимости заданы для install, а команды есть только у setup. Если файлы src нужны для этих команд, перенесите маски из stageDependencies.install в stageDependencies.setup. Если нужна именно стадия install, добавьте инструкции shell.install; если зависимость лишняя — удалите её.

Подробнее — зависимость от изменений в Git-репозитории.

Проверка werf-giterminism.yaml

Исправьте неизвестные и опечатанные ключи в werf-giterminism.yaml: строгая проверка схемы больше не позволяет молча игнорировать их.

Какие образы собираются и выводятся

werf build и другие команды, запускающие сборку, теперь по умолчанию используют --final-images-only=true, как уже делали converge, render, export, plan, lint и bundle publish. «Сиротские» нефинальные образы, на которые не ссылается ни один финальный образ, больше не собираются по умолчанию.

werf config list также по умолчанию выводит только финальные образы; его устаревший алиас --images-only удалён.

Чтобы сохранить прежнее поведение:

werf build --final-images-only=false
werf config list --final-images-only=false

Сервер синхронизации

werf v3 больше не использует сервер синхронизации, включая публичный synchronization.werf.io. Если вы запускали собственный сервер, для v3 он больше не нужен. Отключайте его только после перехода всех клиентов, которые им пользуются; оставшимся клиентам v2 он ещё может быть нужен.

Buildah

Нативный Buildah-бэкенд перешёл с CNI/slirp4netns на netavark/pasta. До обновления подготовьте окружение в зависимости от того, как вы запускаете werf.

Официальный образ werf

Обновите контейнерный образ werf до v3, а не только бинарь внутри него. netavark уже включён в образ; для запуска werf в этом контейнере отдельно устанавливать его на хост runner не нужно.

Официальные Ubuntu-образы werf теперь основаны на Ubuntu 24.04. Если вы создаёте на их основе собственные образы, пересоберите и проверьте их.

Для rootless-сборки с настройкой сети также проверьте наличие pasta внутри контейнера при условиях, описанных ниже: одного netavark недостаточно. Если pasta отсутствует, добавьте её в свой производный образ.

Собственная установка или образ

Если вы устанавливаете werf непосредственно на хост или используете собственный контейнерный образ, убедитесь, что зависимости доступны в среде выполнения werf:

Компонент Где требуется
netavark Везде, где запускается Buildah-бэкенд, включая chroot без сетевых инструкций. Без него инициализация бэкенда завершится ошибкой.
pasta из пакета passt Для rootless-сборки, которая настраивает сеть. Не вызывается при network: host, network: none и в режиме chroot.

netavark должен находиться в одном из каталогов /usr/local/libexec/podman, /usr/local/lib/podman, /usr/libexec/podman, /usr/lib/podman — поиск по $PATH не выполняется. Для pasta используются эти каталоги и $PATH.

Изменения сетевых настроек

Эти изменения действуют и внутри официального образа, и при других способах запуска.

Проверьте настройки сети. Для нестадийных Dockerfile-сборок на нативном Buildah теперь учитываются network: и --backend-network; раньше они молча игнорировались. Поддерживаются только default, host, none: bridge и имена Docker-сетей теперь вызывают ошибку.

Ограничения и совместимость:

  • Для образов с staged: true настройка сети уровня образа по-прежнему игнорируется; действует только RUN --network= конкретной инструкции.
  • В native-chroot Buildah принудительно использует хостовую сеть, поэтому network: none не обеспечивает изоляцию.
  • Поддержка CNI исключена при компиляции и не может быть восстановлена. slirp4netns можно вернуть на отдельном хосте через CONTAINERS_CONF_OVERRIDE: default_rootless_network_cmd="slirp4netns" в секции [network].
  • Это не миграция конфигурации системного Podman/Buildah: werf не читает и не перезаписывает ${graphroot}/defaultNetworkBackend. Если там записано cni, значение сохраняется и продолжает влиять на системный CLI, использующий тот же graphroot.

Деплой

Перед первым werf converge проверьте werf plan: изменения values и правил исключения файлов могут повлиять на манифесты без предупреждения.

Замена удалённых команд werf helm

Команды деплоя и просмотра релизов внутри werf helm удалены. Для проектов werf используйте отдельные команды:

Было — v2 Стало — v3
werf helm install / werf helm upgrade werf converge для установки или обновления проекта
werf helm template werf render
werf helm lint werf lint
werf helm list werf release list
werf helm get … / werf helm status werf release get --release NAME --namespace NAMESPACE
werf helm history NAME werf release history --release NAME --namespace NAMESPACE
werf helm rollback NAME REVISION werf rollback --release NAME --namespace NAMESPACE --revision REVISION
werf helm uninstall NAME werf dismiss --release NAME --namespace NAMESPACE
werf helm test Используйте отдельную команду helm test; замены внутри werf нет.
werf helm plugin Управляйте плагинами и запускайте их через Helm CLI напрямую; werf больше не загружает Helm-плагины.

Это замены рабочих сценариев, а не точные алиасы. converge, render и lint работают с проектом werf, а не с позиционными аргументами Helm RELEASE CHART. Проверьте --help новой команды, явно задайте нужные release и namespace и адаптируйте скрипты разбора вывода. Например, release get --print-values включает вычисленные values в структурированный вывод, а не повторяет вывод helm get values. Для работы с отдельными Helm-чартами используйте Helm CLI напрямую.

werf helm secret и команды работы с чартами, например werf helm dependency, сохраняются; вся группа werf helm не удалена.

Values и переменные окружения

Где Было — v2 Стало — v3
Шаблоны основного чарта и зависимостей .Values.global.env .Values.global.werf.env
Выбор хранилища релизов HELM_DRIVER WERF_RELEASE_STORAGE

Старый ключ .Values.global.env может превратиться в пустое значение без ошибки. Для временной совместимости можно задать WERF_LEGACY_VALUES_GLOBAL_ENV=1.

Без замены HELM_DRIVER werf использует хранилище релизов по умолчанию, а не ранее указанное этой переменной. Переменные путей Helm — HELM_CACHE_HOME, HELM_CONFIG_HOME, HELM_DATA_HOME — продолжают работать.

Чарты и бандлы

.helmignore теперь действует при чтении чарта. Исключённые файлы исчезают из сформированных манифестов и публикуемого бандла без предупреждения.

  • Даже без .helmignore правила Helm по умолчанию исключают файлы и директории, начинающиеся с точки, непосредственно в templates/. Директории исключаются вместе с содержимым.
  • ** теперь вызывает ошибку, хотя раньше не оказывал эффекта.
  • Ведущий ! раньше не оказывал эффекта. Теперь он исключает всё, что не подошло под маску, как правило, оставляя чарт пустым. Не используйте его для отмены предыдущих исключений, как в .gitignore.

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

werf bundle publish теперь использует --helm-compatible-chart=true по умолчанию. Имя в Chart.yaml публикуемого бандла становится последним компонентом пути репозитория; меняются .Chart.Name и пути шаблонов. Чтобы сохранить имя из вашего Chart.yaml, передайте:

werf bundle publish --helm-compatible-chart=false

Режим совместимости AllowMissedSecretKeyMode из v1.2 удалён. При этом bundle publish по-прежнему не требует ключ секретов по умолчанию: значения секретов обрабатываются без расшифровки другим механизмом.

Зашифрованные секреты

Старый клиент не сможет прочитать секрет, записанный v3; возможности записать прежний формат нет. Соблюдайте порядок обновления:

  1. Обновите все окружения, читающие секреты репозитория, до werf v3 или nelm v2: локальные машины, CI-задачи и задачи, применяющие сохранённые deploy plans.
  2. Только после этого создавайте, редактируйте или ротируйте секреты. После перешифрования старый werf или nelm не должен работать с репозиторием.
Было — v2 Стало — v3
Секреты в формате AES-CBC Старые значения продолжают расшифровываться; новые записи используют новый формат.
Исходный YAML-тип зашифрованного значения не сохранялся Для новых YAML-значений сохраняются тип и стиль.

На что обратить внимание:

  • Новый формат распознаёт повреждённый ciphertext и неверный ключ.
  • Ciphertext целого secret-файла по-прежнему можно использовать как значение в secret-values.yaml.
  • Целые secret-файлы используют формат 2, значения в secret-values.yaml — формат 3. Автоматическое различение не даёт интерпретировать целый secret как YAML-метаданные.
  • Старые зашифрованные скаляры остаются строками. Чтобы восстановить число, boolean, timestamp или другой тип, введите значение заново через werf helm secret values edit.
  • Комментарии у зашифрованных значений сохраняются открытым текстом. Не записывайте в них секреты.

Очистка registry

Само обновление werf не удаляет старые образы, но cleanup v3 может удалить образы v2 по политикам сохранения. Версия не даёт им отдельной защиты. Сохраните нужные для отката теги в файле --keep-list, по одному тегу стадии на строку. Не полагайтесь только на защиту Kubernetes: на образ для отката уже может не ссылаться ни один сканируемый ресурс.

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

werf cleanup --repo registry.example.com/app --dry-run --keep-list keep-list.txt

Если настроены --final-repo и --meta-repo, передайте те же значения, что и при сборке. Убедитесь, что сканирование охватывает кластеры и namespaces, использующие эти образы; --without-kube отключает защиту Kubernetes. Не используйте werf purge для удаления только образов v2: он удаляет образы проекта без политик сохранения cleanup.

Отдельный --meta-repo необязателен. Без него метаданные остаются в --repo; само обновление не требует их переноса. Если выносите метаданные существующего проекта в отдельный репозиторий:

  1. На время перехода приостановите периодическую очистку и старые задания v2, пишущие в тот же репозиторий.
  2. Из каталога проекта перенесите накопленные метаданные до первой очистки с --meta-repo:

    werf meta-repo migrate --from registry.example.com/app --to registry.example.com/app-meta
    
  3. Во всех последующих командах v3, включая сборку, cleanup и purge, используйте одинаковый --meta-repo registry.example.com/app-meta. Сами образы остаются в --repo; переносятся только метаданные. По умолчанию оригиналы удаляются после проверки копий; --remove-source=false сохраняет их.
  4. Повторно проверьте cleanup с --dry-run и новым --meta-repo, затем возобновите задание очистки на v3. Не возвращайте cleanup v2 на мигрированный репозиторий: он не видит актуальные метаданные в новом месте.

Добавление --meta-repo само по себе не переносит старые метаданные. Новые записи идут в отдельный репозиторий, а оставшиеся в --repo метаданные cleanup больше не видит. Поэтому он может удалить образы, которые следовало сохранить. Защитный маркер проверяет одинаковый адрес метаданных в последующих командах, а не завершённость миграции. meta-repo detach только снимает защиту и не переносит метаданные обратно.

Подробнее — очистка container registry и отдельный репозиторий метаданных.