open atlas
↑ К треку
Деплой и инфра DEP · 10 · 04

Helm: чарты и values

Helm — пакетный менеджер Kubernetes. Chart шаблонизирует манифесты плейсхолдерами Go-template; values переопределяют их под окружение; а install/upgrade/rollback ведут именованный версионированный release, которого голый kubectl apply не даёт.

DEP Middle ◷ 16 min
Уровень
ОсновыJuniorMiddleSenior

У тебя один сервис в трёх окружениях. Dev хочет 1 реплику и образ :dev; staging — 2 и :rc; prod — 6, другой бюджет ресурсов и запиненный тег :1.8.3. Всё остальное в манифесте идентично. Поэтому команда копирует deployment.yaml в три папки, и теперь изменение readiness-пробы надо вносить руками в трёх местах — и кто-то всегда один пропускает. Хуже: когда прод-раскатка падает в 2 ночи, у kubectl apply нет «отмены». Нет записи, каким был предыдущий рабочий манифест, нет одной команды, чтобы его вернуть. Ты диффишь YAML против истории своего шелла.

Проблема: голый YAML дублируется, а у kubectl apply нет отмены

У обычного YAML Kubernetes две структурные дыры, как только ты гоняешь одно приложение больше чем в одном месте. Первая — дублирование: окружения отличаются горсткой значений — число реплик, тег образа, лимиты ресурсов, hostname, — но у YAML нет параметров, поэтому ты копируешь весь набор манифестов на окружение и держишь их в синхроне руками. Дрейф неизбежен. Вторая — нет единицы релиза: kubectl apply -f отправляет текущие файлы в кластер и забывает. Он не записывает «это версия 4 my-api», не умеет связать Deployment + Service + ConfigMap + Ingress в один атомарный объект и не знает понятия отката к предыдущей версии. Хочешь отменить — реконструируй старый YAML сам.

Helm — де-факто пакетный менеджер Kubernetes — закрывает обе дыры. Он вводит единицу упаковки (chart), механизм параметризации (values) и stateful версионированную единицу деплоя (release).

Chart — это пакет: templates + значения по умолчанию + метаданные

Chart — это директория (или упакованный .tgz) с фиксированной раскладкой. Три части, важные с первого дня:

my-api/
  Chart.yaml          # метаданные: name, version, appVersion, dependencies
  values.yaml         # значения по умолчанию (публичный API чарта)
  templates/
    deployment.yaml   # манифесты K8s, но с плейсхолдерами Go-template
    service.yaml
    _helpers.tpl      # переиспользуемые сниппеты шаблонов

templates/ держит обычные манифесты Kubernetes с плейсхолдерами Go-template, вбитыми в места, которые меняются. Helm рендерит эти шаблоны против дерева values, чтобы получить финальный плоский YAML, и шлёт его в кластер.

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-api
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
        - name: api
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources:
            limits:
              memory: {{ .Values.resources.limits.memory }}

values.yaml поставляет значения по умолчанию — и заодно служит документированным публичным интерфейсом чарта:

# values.yaml (значения по умолчанию)
replicaCount: 1
image:
  repository: registry.example.com/my-api
  tag: dev
resources:
  limits:
    memory: 256Mi

Values переопределяют шаблоны под окружение

Один и тот же chart рендерит разные манифесты, потому что ты кормишь его разными values. Держишь по одному небольшому файлу на окружение и передаёшь его при install/upgrade через -f или переопределяешь отдельные ключи через --set. Приоритет слоистый: values.yaml чарта — база, каждый файл -f переопределяет её слева направо, а флаги --set бьют всё.

# values-prod.yaml — только то, что отличается от значений по умолчанию
replicaCount: 6
image:
  tag: "1.8.3"
resources:
  limits:
    memory: 1Gi
# один chart, три окружения — единственная разница в values
helm upgrade --install my-api ./my-api -f values-prod.yaml
helm upgrade --install my-api ./my-api -f values-staging.yaml --set image.tag=rc-42

Это несущая идея: values — это граница окружения. Шаблон кодирует форму твоего деплоя один раз; values несут факты, специфичные для окружения. Определение readiness-пробы ровно одно на сопровождение, и dev/staging/prod больше не могут разъехаться в частях, которые должны быть идентичны.

Почему это работает

Держи файлы values под окружение тонкими — только ключи, которые реально отличаются от values.yaml. Если ты копируешь весь файл значений по умолчанию на окружение, ты только что заново изобрёл проблему дублирования, ради решения которой Helm и существует, — просто теперь она спрятана на уровень ниже. Дисциплина такая: values.yaml чарта — единственный источник формы и разумных значений по умолчанию; каждый файл values под окружение — короткий diff против него.

Releases: install, upgrade, rollback как одна версионированная единица

Когда ты helm install (или helm upgrade --install) chart, Helm создаёт именованный release и записывает пронумерованную ревизию ровно того, что задеплоил, храня её как Secret в кластере. Каждый helm upgrade поднимает номер ревизии. Поскольку Helm помнит каждую ревизию, helm rollback my-api 4 — это одна команда, которая заново применяет известно-хорошее прошлое состояние, — «отмена», которой у kubectl apply никогда не было. helm uninstall удаляет ресурсы всего release разом. Это превращает деплой из «кучи YAML, которую я впихнул в API-сервер» в атомарную, версионированную, обратимую транзакцию над именованным набором.

helm upgrade --install my-api ./my-api -f values-prod.yaml  # -> ревизия 5
helm history my-api                                         # все ревизии
helm rollback my-api 4                                      # атомарная отмена к рабочему состоянию

kubectl apply vs Helm, кратко

ВозможностьГолый kubectl apply -fHelm
Шаблонизация / параметрыНет — статический YAML, копия на окружениеПлейсхолдеры Go-template, заполняемые из values
Много окруженийДубли манифестов, ручной синхрон, дрейфОдин chart, тонкий файл values на окружение
Release / rollbackНет единицы release, нет встроенной отменыИменованный release, пронумерованные ревизии, helm rollback
Упаковка / шарингРазрозненные файлы в репозиторииChart .tgz, версионированный, в chart-репозитории

Шаринг и переиспользование: репозитории и subcharts

Зачем писать StatefulSet для Postgres с нуля, если production-grade чарты уже существуют, проверены на практике и несут разумные настройки по умолчанию? Именно здесь экосистема чартов окупается.

Чарты — распространяемые артефакты. Публичные chart-репозитории — самый известный Bitnami — публикуют production-grade чарты для готовой инфраструктуры (Postgres, Redis, nginx), так что тебе не надо писать руками stateful-set под базу. Можно и композировать: chart может объявить зависимости (subcharts) в Chart.yaml, а values родителя могут переопределить values сабчарта, так что зонтичный chart связывает твоё приложение с зависимостями как один release.

lesson.inset.warn

Флаг Helm --reuse-values переносит values предыдущего release во время upgrade, что звучит удобно, но молча маскирует изменения, которые ты внёс в values.yaml и в значения по умолчанию новой версии чарта. Лучше передавать свои файлы -f явно на каждый upgrade, чтобы отрендеренный вывод был чистой функцией от chart + видимых тебе values, а не от накопленного скрытого состояния прошлых ревизий.

Заметки сеньора: никогда не апгрейдь вслепую

Две практики отделяют безопасный Helm-воркфлоу от опасного. Предпросмотр до применения. helm upgrade --dry-run рендерит манифесты, не трогая кластер; широко используемый плагин helm diff upgrade показывает точное изменение против живого release, так что ты видишь «это удалит PVC» до того, как это случится, а не после. Версионируй всё. Chart несёт две версии в Chart.yaml: version (собственная версия чарта, поднимай при любом изменении чарта) и appVersion (приложение, которое он поставляет). Относись к чартам как к коду — пинни версию чарта, которую используют твои окружения, и поднимай её осознанно. И помни про ловушку upgrade-vs-recreate: правка неизменяемого поля (spec у Job, clusterIP у Service, некоторые поля volume) не патчится на месте; upgrade падает или, в зависимости от ресурса, форсит пересоздание, которое может означать даунтайм. Читай diff, знай, какие поля неизменяемы, и планируй раскатку — helm rollback это твоя страховка, а не стратегия.

Выбери лучший вариант

Ты гоняешь один сервис в dev, staging и prod, отличающихся только числом реплик, тегом образа и лимитом памяти. Нужны безболезненная конфигурация под окружения и реальный путь отката. Выбери подход.

Викторина

Прод-helm upgrade выкатил битый конфиг, и сервис начал отдавать ошибки. Какое самое быстрое корректное восстановление и почему оно возможно?

Викторина

Где в чарте должна жить разница между dev и prod под окружение (реплики, тег образа)?

Вспомните перед уходом
  1. 01
    Объясни, как один chart Helm выдаёт разные манифесты для dev, staging и prod, назвав три части чарта и как работает приоритет values.
  2. 02
    Почему Helm может откатить битый деплой, а kubectl apply нет, и что прогнать перед upgrade, чтобы откат не понадобился?
Итог

У голого YAML Kubernetes две дыры, как только приложение живёт больше чем в одном месте: он дублирует всё идентичное между окружениями, а у kubectl apply нет единицы release или отката. Теперь, когда унаследуешь кластер, где кто-то годами делал kubectl apply -f по трём окружениям со скопированными манифестами, ты знаешь путь: один chart, один тонкий файл values на окружение и журнал release, делающий helm rollback твоей спасательной командой в 2 ночи. Helm — пакетный менеджер Kubernetes — закрывает обе. Chart — это пакет: метаданные Chart.yaml, templates/ с манифестами с плейсхолдерами Go-template и values.yaml со значениями по умолчанию и публичным интерфейсом чарта. Один и тот же chart рендерит разные манифесты, потому что values переопределяют шаблоны под окружение — тонкий файл values на окружение, переданный через -f, или отдельные ключи через —set, наслаиваемые база-переопределение-флаг. Values — это граница окружения: форма живёт в шаблоне один раз, факты окружения — в маленьких файлах values, поэтому dev/staging/prod не могут разъехаться. Каждый деплой — именованный пронумерованный release, поэтому helm upgrade поднимает ревизию, которую Helm хранит, а helm rollback заново применяет известно-хорошую атомарно — отмену, которой не было у apply. Переиспользуй готовую инфраструктуру из публичных chart-репозиториев вроде Bitnami и композируй через зависимости-subcharts. И никогда не апгрейдь вслепую: helm —dry-run и helm diff предпросматривают изменение, версионируй чарты через version и appVersion в Chart.yaml и следи за ловушкой upgrade-vs-recreate, где неизменяемые поля форсят разрушительное пересоздание.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.