
Каждое мажорное обновление Helm сопровождалось изменением способа развёртывания в кластерах Kubernetes. Поэтому на фоне выхода нового мажорного релиза — V4.0.0 — предлагаю посмотреть на путь изменений в методах развёртывания.
Helm v2, 2WM
Helm v2 вышел 17 ноября 2017 года и уже давно перешёл в статус legacy. Основным алгоритмом был 2WM (2 way merge), который формировал JSON-патч, «догонявший» состояние предыдущего релиза к текущему.
Верхнеуровневая логика развёртывания выглядела следующим образом:
Загрузка состояния предыдущего релиза из Secret.
Рендер шаблона из чарта текущего релиза.
Сравнение манифестов 1 и 2 и формирование патча с вносимыми изменениями.
Применение патча к кластеру.
Запись нового релиза в Secret.

Этот алгоритм не учитывал live-состояние в кластере K8s, из-за чего любое ручное вмешательство или изменения конфигурации не через Helm приводило к конфликтам и рассинхронизации декларированного состояния в чартах и состояния в кластере.
За принятие решений об изменениях в Helm'е отвечал Tiller, именно он взаимодействовал с API K8s. В открытом исходном коде можно найти использование двух методов для разных разворачиваемых ресурсов:
Если ресурс есть в OpenAPI-схеме и имеет аннотации для strategic merge, то использовали strategicpatch.CreateTwoWayMergePatch.
Если ресурс отсутствует в схеме, является нестандартным или кастомным (CRD), то использовали jsonpatch.CreateMergePatch.
Разница между методами в том, что 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-состояние релиза).
Алгоритм формирует несколько патчей:
С → M — патч, необходимый для перехода из состояния в кластере к текущему релизу. В патче сохраняют только добавление или изменение данных, удаление из патча намеренно убирают.
O → M — патч, необходимый для перехода из предыдущего к текущему релизу. В патче сохраняют только удаление данных, добавление или изменение данных из патча убирают.
2 → 1 — итоговый патч, который применяется к кластеру.
Верхнеуровневая логика развёртывания изменилась:
Загрузка состояния предыдущего релиза из Secret.
Получение текущего состояния из кластера.
Рендер шаблон из манифестов текущего релиза.
Сравнение релизов и формирование патча с вносимыми изменениями.
Применение патча к кластеру.
Запись нового релиза в Secret.

Однако и этот алгоритм можно было привести в состояние рассинхронизации с помощью ручных изменений и неудачных релизов.
Tiller удалили и клиент Helm стал сам принимать решения. В открытом коде реализация не сильно поменялась, кроме используемых методов (2WM → 3WM):
Если ресурс есть в OpenAPI-схеме и имеет аннотации для strategic merge, то использовали strategicpatch.CreateThreeWayMergePatch.
Если ресурс отсутствует в схеме, является нестандартным или кастомным (CRD), то использовали jsonmergepatch.CreateThreeWayJSONMergePatch.
Аналогично второму Helm разница между методами в том, что strategicpatch.CreateThreeWayMergePatch знает структуры данных и эффективнее с ними работает. При этом jsonmergepatch.CreateThreeWayJSONMergePatch более агрессивен при удалении структур, которые убрали в том релизе, но они могли быть в live-состоянии релиза.
Helm v4, SSA
Самая свежая мажорная версия Helm вышла 3 ноября 2025 года и принесла с собой множество изменений. Но основным нововведением, в контексте этой статьи, стала поддержка SSA (Server side apply).
SSA — это механизм применения изменений к ресурсам Kubernetes, в котором слияние конфигураций происходит на стороне сервера, а не клиента. Это решает проблемы предыдущих методов (strategicpatch, jsonmergepatch). API-сервер определяет, какие поля изменились, кто какие поля контролирует (manager) и как безопасно применить изменения.
Документация Kubernetes по SSA.
Верхнеуровневая логика развёртывания стала выглядеть гораздо проще:
Рендер шаблона из манифестов текущего релиза.
Применение шаблона к кластеру — SSA Patch.
Запись нового релиза в Secret.

Функциональность 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.sh/hook-weight) по возрастанию, от отрицательных к положительным.
Если у хуков одинаковый вес, то они сортируются по типу ресурса. Helm использует зафиксированный порядок развёртывания для стандартных ресурсов K8s kind_sorter.go.
Порядок зафиксирован и в документации, но периодически устаревает.
Если у хуков одинаковый вес и их ресурс отсутствует в списке kind_sorter.go, то сортировка идёт по их типу (Kind) по алфавиту по возрастанию.
Но порядок обновления определяется не только хуками, полный порядок выглядит так:
Кастомные CRD-ресурсы: всё, что расположено в папке crd/ в чарте.
Хуки pre-install, pre-upgrade.
Стандартные ресурсы без хуков по порядку из kind_sorter.go.
Неизвестные ресурсы без хуков, которые отсутствуют в kind_sorter.go. Неизвестные ресурсы сортируются по их типу (Kind) по алфавиту по возрастанию.
Хуки post-install, post-upgrade.
Заключение
Эволюция Helm от v2 к v4 отражает общий тренд в экосистеме K8s: передача логики управления состоянием от клиента к API-серверу. Если Helm v2 игнорировал реальное состояние кластера, а v3 пытался компенсировать это сложной клиентской логикой 3WM, то Helm v4, опираясь на Server-Side Apply, делегирует слияние и управление полями самому Kubernetes. Это не только повышает надёжность и предсказуемость развёртываний, но и обеспечивает корректную совместную работу с другими контроллерами и инструментами. При этом Helm сохраняет обратную совместимость и гибкость через хуки и флаги, позволяя командам плавно адаптироваться к новым возможностям.