Каждое мажорное обновление Helm сопровождалось изменением способа развёртывания в кластерах Kubernetes. Поэтому на фоне выхода нового мажорного релиза — V4.0.0 — предлагаю посмотреть на путь изменений в методах развёртывания.

Helm v2, 2WM

Helm v2 вышел 17 ноября 2017 года и уже давно перешёл в статус legacy. Основным алгоритмом был 2WM (2 way merge), который формировал JSON-патч, «догонявший» состояние предыдущего релиза к текущему.

Верхнеуровневая логика развёртывания выглядела следующим образом:

  1. Загрузка состояния предыдущего релиза из Secret.

  2. Рендер шаблона из чарта текущего релиза.

  3. Сравнение манифестов 1 и 2 и формирование патча с вносимыми изменениями.

  4. Применение патча к кластеру.

  5. Запись нового релиза в Secret.

Helm v2
Helm v2

Этот алгоритм не учитывал live-состояние в кластере K8s, из-за чего любое ручное вмешательство или изменения конфигурации не через Helm приводило к конфликтам и рассинхронизации декларированного состояния в чартах и состояния в кластере.

За принятие решений об изменениях в Helm'е отвечал Tiller, именно он взаимодействовал с API K8s. В открытом исходном коде можно найти использование двух методов для разных разворачиваемых ресурсов:

Разница между методами в том, что strategicpatch.CreateTwoWayMergePatch эффективнее обрабатывает сложные структуры. Для массивов и словарей он будет генерировать меньшие по размеру патчи, учитывая описанные в OpenAPI-схеме patch strategy и patch merge key.

Helm v3, 3WM

Helm 3-ей версии вышел 12 ноября 2019 года и на данный момент активно используется. В нём на смену 2WM пришёл 3WM (3 way merge). Алгоритм формирует несколько JSON-патчей, чтобы так же «догнать» состояние предыдущего релиза к текущему, но учитывая live-состояние. Чтобы не запутаться в логике работы 3WM, зафиксируем следующие сокращения:

  • O — original (предыдущий релиз);

  • M — modified (текущий релиз);

  • C — current (Live-состояние релиза).

Алгоритм формирует несколько патчей:

  1. С → M — патч, необходимый для перехода из состояния в кластере к текущему релизу. В патче сохраняют только добавление или изменение данных, удаление из патча намеренно убирают.

  2. O → M — патч, необходимый для перехода из предыдущего к текущему релизу. В патче сохраняют только удаление данных, добавление или изменение данных из патча убирают.

  3. 2 → 1 — итоговый патч, который применяется к кластеру.

Верхнеуровневая логика развёртывания изменилась:

  1. Загрузка состояния предыдущего релиза из Secret.

  2. Получение текущего состояния из кластера.

  3. Рендер шаблон из манифестов текущего релиза.

  4. Сравнение релизов и формирование патча с вносимыми изменениями.

  5. Применение патча к кластеру.

  6. Запись нового релиза в Secret.

Helm v3
Helm v3

Однако и этот алгоритм можно было привести в состояние рассинхронизации с помощью ручных изменений и неудачных релизов.

Tiller удалили и клиент Helm стал сам принимать решения. В открытом коде реализация не сильно поменялась, кроме используемых методов (2WM → 3WM):

Аналогично второму Helm разница между методами в том, что strategicpatch.CreateThreeWayMergePatch знает структуры данных и эффективнее с ними работает. При этом jsonmergepatch.CreateThreeWayJSONMergePatch более агрессивен при удалении структур, которые убрали в том релизе, но они могли быть в live-состоянии релиза.

Helm v4, SSA

Самая свежая мажорная версия Helm вышла 3 ноября 2025 года и принесла с собой множество изменений. Но основным нововведением, в контексте этой статьи, стала поддержка SSA (Server side apply).

SSA — это механизм применения изменений к ресурсам Kubernetes, в котором слияние конфигураций происходит на стороне сервера, а не клиента. Это решает проблемы предыдущих методов (strategicpatch, jsonmergepatch). API-сервер определяет, какие поля изменились, кто какие поля контролирует (manager) и как безопасно применить изменения.

Документация Kubernetes по SSA.

Верхнеуровневая логика развёртывания стала выглядеть гораздо проще:

  1. Рендер шаблона из манифестов текущего релиза.

  2. Применение шаблона к кластеру — SSA Patch.

  3. Запись нового релиза в Secret.

Helm v4
Helm v4

Функциональность SSA включается флагом --server-side true, а для решения конфликтов между менеджерами и перехвата контроля есть флаг --force-conflicts. Но будьте внимательны, 3WM ещё используется клиентом Helm и может быть включён флагом --server-side false или --take-ownership.

Флаг --take-ownership имеет скрытую логику: еcли у вас не будет указан флаг --server-side, а предыдущий релиз был установлен по 3WM, то и текущий релиз тоже установится с логикой 3WM :

updateThreeWayMergeForUnstructured := i.TakeOwnership && !i.ServerSideApply // Use three-way merge when taking ownership (and not using server-side apply)

Порядок обновления ресурсов

В логике развёртывания релиза есть ещё одна интересная механика: порядок обновления ресурсов в кластере и возможность влиять на него. Механизм хуков в Helm предлагает возможности тонкой настройки с помощью выставления весов для конкретных манифестов и формирования собственного порядка обновления под нужды команды.

Документация Helm по хукам.

Логика работы хуков следующая:

  1. Хуки сортируются по весу (helm.sh/hook-weight) по возрастанию, от отрицательных к положительным.

  2. Если у хуков одинаковый вес, то они сортируются по типу ресурса. Helm использует зафиксированный порядок развёртывания для стандартных ресурсов K8s kind_sorter.go.

  3. Порядок зафиксирован и в документации, но периодически устаревает.

  4. Если у хуков одинаковый вес и их ресурс отсутствует в списке kind_sorter.go, то сортировка идёт по их типу (Kind) по алфавиту по возрастанию.

Но порядок обновления определяется не только хуками, полный порядок выглядит так:

  1. Кастомные CRD-ресурсы: всё, что расположено в папке crd/ в чарте.

  2. Хуки pre-install, pre-upgrade.

  3. Стандартные ресурсы без хуков по порядку из kind_sorter.go.

  4. Неизвестные ресурсы без хуков, которые отсутствуют в kind_sorter.go. Неизвестные ресурсы сортируются по их типу (Kind) по алфавиту по возрастанию.

  5. Хуки post-install, post-upgrade.

Заключение

Эволюция Helm от v2 к v4 отражает общий тренд в экосистеме K8s: передача логики управления состоянием от клиента к API-серверу. Если Helm v2 игнорировал реальное состояние кластера, а v3 пытался компенсировать это сложной клиентской логикой 3WM, то Helm v4, опираясь на Server-Side Apply, делегирует слияние и управление полями самому Kubernetes. Это не только повышает надёжность и предсказуемость развёртываний, но и обеспечивает корректную совместную работу с другими контроллерами и инструментами. При этом Helm сохраняет обратную совместимость и гибкость через хуки и флаги, позволяя командам плавно адаптироваться к новым возможностям.

Комментарии (0)