Почему Helm 3 сменили на Nelm

Уровень: advanced ~50 мин Практика: Vikunja (AGPL-3.0)

Что нужно знать перед уроком

  • M4.02 — Werf-специфика чарта — нужна структура werf-чарта перед разбором механики применения этого чарта в кластер

Что нужно знать перед уроком

M4 уроки 1–2 — структура чарта. Здесь — самое важное архитектурное отличие Nelm от Helm 3: как именно вычисляется, какие изменения применить к кластеру.

Теория

Helm 3 Way Merge (3WM) — механика и её слабое место

Когда Helm 3 обновляет релиз (helm upgrade), он вычисляет патч на основе трёх источников:

  1. Live-состояние ресурса в кластере (что реально сейчас там есть).
  2. Предыдущий манифест релиза (что было применено на прошлой ревизии, хранится в истории релиза Helm).
  3. Новый манифест (что должно быть применено теперь).

Патч формируется на стороне клиента (сам Helm вычисляет diff), исходя из предположения, что все предыдущие манифесты релиза были успешно применены к кластеру ровно так, как записано в истории. Проблема: это предположение не всегда верно. Если кто-то вручную поправил ресурс через kubectl edit (внешняя правка, не через Helm), или предыдущий helm upgrade завершился частичной ошибкой — live-состояние расходится с тем, что Helm «думает», что применил. В этом случае 3-Way Merge вычисляет патч на основе неверных предположений о текущем состоянии — результат непредсказуем: то, что должно было измениться, может не измениться, а то, что не должно было — измениться неожиданно.

Server-Side Apply (SSA) — diff считает сам API-сервер

Nelm с самого начала (архитектурно, не как миграция) использует другой механизм — Server-Side Apply, встроенный в сам Kubernetes API начиная с версии 1.16 (стабильно). Ключевое отличие: diff вычисляет сам kube-apiserver, а не клиент. Клиент (Nelm) отправляет декларацию желаемого состояния (“field manager” с указанием, какие поля принадлежат именно этому управляющему агенту), а сервер сам определяет, что изменилось, учитывая актуальное реальное состояние ресурса в этот самый момент — без необходимости доверять записи в локальной истории релизов о том, что «должно было» быть применено ранее.

flowchart TB subgraph "Helm 3 — client-side 3-Way Merge" A1["Live state"] --> D1["Diff вычисляет КЛИЕНТ (Helm)"] A2["Предыдущий манифест из истории релиза"] --> D1 A3["Новый манифест"] --> D1 D1 --> P1["Патч отправляется в кластер"] end subgraph "Nelm — Server-Side Apply" B1["Новый манифест + field manager"] --> D2["Diff вычисляет СЕРВЕР (kube-apiserver)"] D2 --> P2["Patch применяется атомарно на сервере"] end

Это устраняет саму причину сбоев 3WM: сервер всегда видит актуальное реальное состояние ресурса, а не полагается на историческую запись о прошлых операциях. Если ресурс был правлен вручную вне Helm/Nelm — SSA корректно учтёт это при вычислении следующего патча (в зависимости от того, какие поля принадлежат какому field manager’у — конфликт полей между разными управляющими агентами явно сигнализируется, а не тихо перезаписывается).

SSA — общепринятый стандарт, а не изобретение werf

Server-Side Apply — не специфичная для Nelm технология, а стандартный механизм самого Kubernetes API, на который перешли и другие крупные инструменты GitOps/деплоя (например, Flux). Nelm просто адаптировал этот подход с самого начала своей архитектуры (полный переписанный движок деплоя, в отличие от Helm 3, который эволюционно нарастил SSA поверх уже существующей 3WM-архитектуры для обратной совместимости) — то есть Nelm не «изобрёл» SSA, а спроектирован изначально вокруг него, без legacy-совместимости с client-side логикой.

Практическое следствие: nelm release plan install

1
nelm release plan install -n myproject -r myproject --set cert-manager.replicaCount=2
Planning release install "myproject" (namespace: "myproject")

┌ Update Deployment/myproject-cert-manager
│     namespace: myproject
│   spec:
│     progressDeadlineSeconds: 600
│ -   replicas: 1
│ +   replicas: 2
│     revisionHistoryLimit: 10
│     selector:
│       matchLabels:
└ Update Deployment/myproject-cert-manager

Planned changes summary for release "myproject" (namespace: "myproject"):
- update: 1 resource(s)

Диагностическое следствие принципа SSA прямо видно в выводе plan install: этот diff — 100% точный, полученный через настоящий dry-run Server-Side Apply (сервер реально просчитывает изменение, просто не применяет его), а не приближённое клиентское предположение, как было бы в 3WM-модели. Именно поэтому Nelm может честно гарантировать точность предпросмотра плана — деталь, критичная при работе с production-релизами Application.

Частые ошибки и подводные камни

  • Считать, что Nelm — это просто «более новая версия Helm с другим CLI». Различие не косметическое: под капотом принципиально другой механизм вычисления изменений (SSA vs 3WM), решающий конкретную структурную проблему исходного Helm 3.
  • Ожидать, что ручные правки через kubectl edit останутся незамеченными при следующем деплое. SSA сервера видит реальное состояние — конфликты полей между управляющими агентами (field managers) будут явно проявляться, а не тихо игнорироваться, как иногда происходило в клиентской модели.
  • Путать SSA (Server-Side Apply, о применении ресурсов) с обычным kubectl apply --server-side. Это тот же базовый механизм Kubernetes API, но Nelm использует его системно и целостно для всего процесса деплоя релиза, а не как отдельную опцию одной команды.

Практика в кластере

Практики в кластере в этом уроке нет — материал концептуальный, первая реальная установка через Nelm — с M4 урока 5.

Практика разработки

🧩 Практика урока: Vikunja · лицензия AGPL-3.0

Смоделируйте ситуацию рассинхрона состояния (иллюстративное упражнение для понимания разницы подходов, без реального деплоя чарта):

  1. Если у вас уже есть тестовый Deployment в кластере из предыдущих модулей (например, из M1), внесите в него ручное изменение через kubectl edit, не связанное с Helm/Nelm-релизом:
1
kubectl edit deployment <name> -n <ns>   # добавьте произвольную аннотацию вручную
  1. Мысленно (или на практике, если у вас настроен тестовый чарт) сравните два подхода: helm upgrade со старой 3WM-логикой полагался бы на историческую запись о том, что «должно быть» в манифесте, потенциально не заметив вашей ручной правки корректно; nelm release plan install покажет вам точный diff, учитывающий реальное текущее состояние ресурса, включая внесённую вами правку.
1
kubectl get deployment <name> -n <ns> -o yaml | grep -A2 annotations

Шпаргалка команд урока

1
nelm release plan install -n <ns> -r <release> <chart-dir>

Вопросы для самопроверки

Кто вычисляет diff в модели 3-Way Merge (Helm 3)?

3WM — клиентский механизм: Helm сам вычисляет патч, полагаясь на три источника, включая предположение об успешности прошлых применений.

Источник: Nelm — README на GitHub

В чём структурная проблема 3-Way Merge?

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

Источник: Nelm — README на GitHub

Кто вычисляет diff при Server-Side Apply?

SSA переносит вычисление патча на сторону сервера — устраняя зависимость от исторических клиентских предположений.

Источник: Nelm — README на GitHub

Является ли Server-Side Apply изобретением специфичным для werf/Nelm?

SSA — часть самого Kubernetes API; Nelm просто спроектирован изначально вокруг него, а не изобрёл этот механизм.

Источник: Nelm — README на GitHub

Почему diff в nelm release plan install называется '100% точным'?

dry-run SSA даёт точный расчёт изменений напрямую от сервера, в отличие от клиентских эвристик 3WM.

Источник: Nelm — README на GitHub

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Matt Butcher, Matt Farina, Josh Dolitsky. Learning Helm. 2019. ISBN 978-1492036781.

Связанные материалы