Helm: чарты, values, релизы
Урок курса «Курс подготовки DevOps-инженеров»
Хронометраж: занятие 60 минут — теория 30 минут, практика 30 минут. Домашняя работа: 1–2 часа.
Кратко о чём урок: Устройство чарта и шаблонов, values и их переопределение, install/upgrade/rollback и хранение состояния релиза, зависимости, hooks, отладка через template и diff-плагин.
1. Что изучаем
После урока вы сможете:
- объяснять, из чего состоит чарт и почему шаблон — не главное в нём;
- предсказывать, какое значение победит, когда values заданы в трёх местах;
- объяснять, где Helm хранит состояние релиза, и читать его штатными командами;
- различать ревизию релиза и ревизию объекта и откатываться осознанно;
- проверять изменение до применения и понимать, чего эта проверка не увидит;
- объяснять, почему правка кластера руками ломает следующий
helm upgrade.
2. Зачем это нужно и где применяется
Блок 12 закончился на том, что у приложения в Kubernetes набирается десяток манифестов: Deployment, Service, ConfigMap, Secret, Ingress или Gateway, пробы, ресурсы, тома. Пока приложение одно и окружение одно, это просто каталог файлов. Проблемы начинаются, когда появляется второе окружение и второе приложение.
Три задачи, которые и создали инструменты вроде Helm:
- **одно описание на несколько окружений.**Разница между dev и prod — это несколько значений (число реплик, домен, размер тома), а не другой набор манифестов. Копировать каталог и править руками — гарантированный дрейф между средами (10.01);
- установка чужого приложения одной командой. Prometheus, Argo CD, Istio, база данных — все они поставляются чартами, и это единственный способ получить их, не собирая двадцать манифестов самому;
- обратимость. У выката в Kubernetes есть откат (13.05), но он про один Deployment. Релиз — это набор объектов, и откатывать надо набор.
Отсюда рабочие ситуации, разобранные в уроке:
- «на dev работает, на prod другие значения» — и надо понять, какое победило;
- «после
helm upgradeизменилось не то, что ожидали» — самая частая заявка по Helm, и причина обычно в одной строке команды; - «
helm upgradeпадает с конфликтом, хотя чарт не менялся» — следствие того, что кто-то правил кластер руками; - «релиз в состоянии
failed, что теперь с приложением» — и надо знать, применилось ли хоть что-нибудь; - «проверили перед выкатом, а установка всё равно упала» — потому что проверяли не тем.
3. Теория (30 минут)
Файлы для работы: blocks/14-kubernetes-operations/examples/14.01-helm/
Стенд:
kind, один узел, Kubernetes v1.37.0, Helm v4.3.0. Версия здесь важна как никогда: Helm 4 применяет объекты через server-side apply, и половина поведения в уроке следует именно из этого. Советы из статей про Helm 3 местами уже неверны. Все опыты идут сHELM_*_HOMEво временном каталоге — настройки Helm на машине не затрагиваются (тот же приём, чтоDOCKER_CONFIGв 08.09).
3.1. Чарт: что в нём есть и что из этого важно
helm create demo разворачивает заготовку — 4 каталога, 12 файлов, 481 строка
в файлах *.yaml и *.tpl, из которых 161 строка приходится на values.yaml.
Соотношение показательно: треть заготовки — не шаблоны, а описание того, что в них
можно менять.
Учебный чарт мы напишем сами и маленьким
(chart/), чтобы видеть каждую строку:
| Файл | Что это |
|---|---|
Chart.yaml |
паспорт: имя, version (версия чарта), appVersion (версия приложения) |
values.yaml |
значения по умолчанию — интерфейс чарта для того, кто его ставит |
templates/*.yaml |
манифесты с подстановками: deployment.yaml, service.yaml |
templates/_helpers.tpl |
именованные фрагменты, файл не становится объектом (точка в начале имени) |
charts/ |
зависимости, скачанные локально |
Две версии в Chart.yaml путают чаще всего. version меняется при правке шаблонов,
appVersion — когда обновилось само приложение. Они не связаны: можно трижды поправить
шаблон при том же образе.
Шаблон превращается в манифест без кластера — это отдельная команда:
helm template web chart
→ kind: Service, name: web-course-app
→ kind: Deployment, name: web-course-app, replicas: 2
объектов: 2
Имя web-course-app собрано из имени релиза и имени чарта — так один чарт ставится
в один кластер многократно. И обратите внимание: шаблонизация целиком клиентская,
кластер о чартах ничего не знает. Это первое, что надо понять про Helm: он не расширение
Kubernetes, а генератор манифестов плюс учёт того, что сгенерировал.
3.2. Values: четыре источника и один победитель
Значения приходят из нескольких мест, и приоритет проверяется одной таблицей (измерено на одном чарте, меняется только команда):
| Как задано | replicas |
APP_VERSION |
|---|---|---|
только values.yaml чарта |
2 | v1 |
-f prod.yaml |
3 | from-file |
--set appVersion=from-set |
2 | from-set |
-f prod.yaml и --set |
3 | from-set |
Порядок такой: значения чарта — слабее файла -f, файл — слабее --set. При нескольких
-f побеждает последний. Логика та же, что у приоритетов переменных Ansible (10.02),
и ошибаются в ней так же часто.
А вот ловушка, которой нет в документации на первой странице и которая стоит простоя.
Значения не «прилипают» к релизу. Ставим с тремя репликами, потом делаем upgrade,
меняя только версию:
install --set replicaCount=3 --set appVersion=v1 → replicas 3
upgrade --set appVersion=v2 → replicas 2 (!), APP_VERSION v2
replicaCount вернулся к значению чарта, потому что в новой команде его не было.
То есть helm upgrade — это не «изменить одно поле», а «применить чарт с теми
значениями, что переданы сейчас». Отсюда два способа не наступить:
helm upgrade web chart --reuse-values --set appVersion=v3 → replicas 3, APP_VERSION v3
helm upgrade web chart -f prod.yaml → значения из файла в git
Второй правильнее: --reuse-values тащит состояние, которое нигде не записано, а файл
значений лежит в репозитории и виден в истории изменений. Это ровно тот вывод, который
мы получали про откат Deployment в 13.05: временная мера против записанного состояния.
3.3. Релиз: где живёт состояние
После helm install в кластере два объекта приложения и ещё один, служебный:
kubectl get secret -l owner=helm
sh.helm.release.v1.web.v1 helm.sh/release.v1
метки: {"name":"web","owner":"helm","status":"deployed","version":"1"}
Состояние релиза — это Secret особого типа в том же пространстве имён. Никакой серверной части у Helm нет (в Helm 2 была, и её убрали): весь учёт — в объектах кластера. Из этого следуют практические вещи. Кто имеет доступ к секретам namespace, тот видит все values релиза, включая пароли, — значит для секретов остаются те же соображения, что в 13.08. И чтобы посмотреть состояние, не нужны чужие инструменты:
| Команда | Отвечает на вопрос |
|---|---|
helm list -o json |
какие релизы есть, какая ревизия, какой статус |
helm get values web |
что переопределили при установке |
helm get values web --all |
какие значения получились в итоге (18 строк против 8) |
helm get manifest web |
какие манифесты применены (2 объекта) |
helm get hooks web |
какие хуки есть у релиза |
Про helm list отдельно: читать его колонки в скриптах нельзя. Я на этом наступил
в этом же уроке — awk '{print $8}' выдал метку времени вместо статуса, потому что
в поле даты пробелы. В скриптах только -o json.
3.4. Ревизии: две разные нумерации
Каждое изменение релиза создаёт новую ревизию и новый Secret:
helm history web
REVISION STATUS DESCRIPTION
1 superseded Install complete
2 superseded Upgrade complete
3 deployed Upgrade complete
ревизия Deployment: 3 секретов состояния: 3
Числа совпали случайно: каждое изменение чарта здесь меняло шаблон пода. Если поправить то, что пода не касается (метку сервиса, размер ресурса другого объекта), ревизия релиза вырастет, а ревизия Deployment — нет. Ревизия релиза — про набор объектов, ревизия Deployment — про шаблон пода (13.05).
Откат устроен так же, как в Deployment, и это стоит запомнить:
helm rollback web 1
4 deployed Rollback to 1
APP_VERSION в кластере: v1, replicas: 2
Откат создаёт новую ревизию, а не возвращает старую. История только растёт;
--history-max по умолчанию 10, дальше старые ревизии вытесняются. И тот же вывод,
что в 13.05: откат — временная мера, дальше правится то, из чего собирается релиз.
3.5. Server-side apply: главное отличие Helm 4
Здесь начинается то, из-за чего к этому уроку нельзя применять советы про Helm 3. Посмотрим, кто владеет полями установленного объекта (механика из 13.03):
kubectl get deploy web-course-app --show-managed-fields
менеджер: helm операция: Apply
менеджер: kube-controller-manager операция: Update
Операция Apply означает server-side apply: Helm 4 по умолчанию (--server-side auto)
применяет объекты так же, как kubectl apply --server-side. Теперь трогаем кластер руками
и пробуем обычный upgrade:
kubectl scale deploy web-course-app --replicas=5
helm upgrade web chart → код 1
conflict with "kubectl" with subresource "scale" using apps/v1: .spec.replicas
replicas после неудачи: 5, статус релиза: failed
helm upgrade не «перетирает» ручную правку, а падает с конфликтом владения полем.
Это то же поведение, что у двух менеджеров в 13.03, только здесь один из них — Helm.
Выход — сказать явно, что вы забираете поле себе:
helm upgrade web chart --force-conflicts → код 0, replicas 2, статус deployed
менеджеры после этого: helm (Apply), kube-controller-manager (Update)
Знакомый по статьям --force здесь не поможет и даже не запустится:
invalid operation: cannot use server-side apply and force replace together. Он относится
к другому механизму (--force-replace, замена объекта целиком) и с server-side apply
несовместим.
Контрольный опыт, без которого вывод был бы неполным: тот же дрейф при клиентском применении.
helm install web chart --server-side=false → менеджер: helm, операция Update
kubectl scale --replicas=5
helm upgrade web chart --server-side=false → код 0, replicas 2
То есть при --server-side=false расхождение правится молча и без ошибки. Разница
поведения — не в Helm как таковом, а в способе применения; по умолчанию в версии 4
он серверный. Мелочь, которую видно здесь же: аннотации
last-applied-configuration Helm не ставит ни в одном режиме — прошлый манифест он
хранит в своём Secret, а не в объекте.
3.6. Проверка до применения: что ловит каждый инструмент
Четыре способа «посмотреть, прежде чем ставить», и они не равноценны. Внесём в шаблон
опечатку в имени поля (imagePullPolicyy) — YAML остаётся валидным, схема нарушена:
| Команда | Код | Поймала? |
|---|---|---|
helm lint chart |
0 | нет |
helm template web chart |
0 | нет |
helm install --dry-run |
0 | нет |
helm install --dry-run=server |
0 | нет |
helm template … | kubectl apply --dry-run=server -f - |
1 | да: unknown field |
helm install по-настоящему |
1 | да: failed to create typed patch, объект не создан |
Строка про --dry-run=server — главная в таблице и самая неожиданная. Серверный
пробный прогон Helm опечатку не увидел, хотя kubectl apply --dry-run=server на том
же отрисованном манифесте её ловит (в 13.03 мы это измеряли). Значит проверка, которой
все доверяют, даёт ложную уверенность, а надёжный порядок — отрисовать и прогнать через
kubectl:
helm template web chart | kubectl apply --dry-run=server -f -
Плагин helm diff отвечает на другой вопрос — «что изменится». Он ставится отдельно,
и на стенде это потребовало --verify=false (plugin source does not support verification), что само по себе повод задуматься о доверии к плагинам:
helm diff upgrade web chart --set appVersion=v3
- value: "v2"
+ value: "v3"
Но у него есть граница, которую надо знать. Правим кластер руками и снова смотрим diff:
kubectl scale deploy web-course-app --replicas=7
helm diff upgrade web chart --set replicaCount=3 → строк вывода 0
Ноль. helm diff по умолчанию сравнивает новый чарт с сохранённым релизом,
а не с фактическим состоянием кластера, — то есть дрейф он не показывает. Сравнение
с кластером включается --dry-run=server, и тогда разница появляется. Это ровно та же
ловушка, что у kubectl diff в 13.03: инструмент отвечает на вопрос «что сделает
команда», а не «чем кластер отличается от репозитория».
3.7. Хуки: как выполнить миграцию перед выкатом
Хук — обычный объект с аннотацией. Job с helm.sh/hook: pre-upgrade,pre-install
выполняется до применения остальных объектов
(chart/templates/migration-hook.yaml):
helm upgrade web chart --set migration.enabled=true → код 0
job: web-course-app-migrate Complete 1/1 7s
логи: миграция схемы
Полезнее посмотреть, что будет при неудаче. Заставим хук завершиться с кодом 1:
helm upgrade … --set migration.exitCode=1 --set appVersion=v9 → код 1
pre-upgrade hooks failed: … Job Failed. failed: 1/1
статус релиза: failed
APP_VERSION в кластере: v1 (просили v9)
Объекты не применились вовсе — упавшая миграция остановила выкат, приложение осталось
на прежней версии. Это и есть причина, по которой миграции вешают на pre-upgrade
(сравните с 07.07, где мы разбирали сами миграции).
Флаг --atomic добавляет к этому автоматический откат:
helm upgrade web chart --atomic … → код 1
5 failed Upgrade "web" failed: pre-upgrade hooks failed…
6 deployed Rollback to 4
статус релиза: deployed
Код возврата 1 — работа не сделана, но релиз снова deployed, а не failed. В пайплайне
это важно: без --atomic неудачный выкат оставляет релиз в состоянии failed, и следующий
запуск начинается из него.
И одна вещь, которая удивляет при уборке: helm uninstall снял приложение и своё
состояние, но Job от хука остался:
объектов приложения: 0, секретов состояния: 0, Job от хука: 1
Так работает hook-delete-policy: before-hook-creation — объект удаляется перед
следующим запуском хука, а не после успеха. Хотите чистоты — hook-succeeded.
3.8. Зависимости
Чарт может тянуть другие чарты. Объявление в Chart.yaml, и helm dependency update
скачивает их в charts/ и пишет Chart.lock:
helm dependency update umbrella → код 0, Saving 1 charts
в charts/: course-app-0.1.0.tgz, Chart.lock: 6 строк
объектов при subchart.enabled=false: 0
объектов при subchart.enabled=true: 2
Чарт-обёртка своих шаблонов не имеет вовсе, поэтому при выключенном условии из него не рождается ни одного объекта, а при включённом появляются объекты подчарта.
Два наблюдения. condition позволяет выключать зависимость значением — так делают
«поставь базу вместе с приложением или подключись к внешней». И Chart.lock — это тот же
самый механизм, что package-lock.json из 07.04: без него version: "^1.0" однажды
приведёт другую версию. Зависимость из локального каталога (file://) годится, чтобы
проверить механизм без сети.
3.9. Сводка: что показали замеры
| Что проверяли | Результат |
|---|---|
helm create |
4 каталога, 12 файлов, 442 строки, из них 161 — values.yaml |
| приоритет values | чарт < -f < --set; при двух -f — последний |
| values между upgrade | не сохраняются: replicaCount вернулся с 3 на 2 |
| состояние релиза | Secret типа helm.sh/release.v1, по одному на ревизию |
helm get values против --all |
8 строк против 18 (зависит от числа переопределений) |
| откат | создаёт новую ревизию (4 Rollback to 1), --history-max = 10 |
| чем применяет Helm 4 | server-side apply: менеджер helm, операция Apply |
дрейф + helm upgrade |
код 1, конфликт владения полем, релиз failed |
| выход из конфликта | --force-conflicts → код 0; --force не работает вовсе |
то же при --server-side=false |
операция Update, дрейф правится молча, код 0 |
| опечатка в имени поля | lint, template, --dry-run, --dry-run=server — не поймали |
| та же опечатка | kubectl apply --dry-run=server — поймал, настоящий install упал |
helm diff при дрейфе |
0 строк — сравнивает с релизом, не с кластером |
провал хука pre-upgrade |
объекты не применились, релиз failed, версия прежняя |
--atomic |
код 1, но автоматический откат и статус deployed |
uninstall |
приложение и состояние удалены, Job хука остался |
| зависимости | Chart.lock из 6 строк; condition включает подчарт (0 против 2 объектов) |
3.10. Примеры и варианты реализации
Локальный стенд. Всё из урока воспроизводится полностью: Helm — клиентский
инструмент, кластеру для него ничего не нужно. Единственное, чего стоит избегать
на стенде, — привыкнуть к --set: локально это удобно, а в рабочем процессе даёт
ту самую ловушку с «непослушными» значениями.
VPS / bare-metal. Добавляется вопрос хранения чартов и значений. Чарт лежит в git рядом с кодом либо в реестре (OCI-репозиторий — тот же реестр образов из 08.09), файлы значений по окружениям — в git, секреты не в них (13.08, 07.03). И отдельно: доступ к namespace означает доступ к values всех релизов в нём, потому что состояние — обычный Secret.
Yandex Cloud (Managed Service for Kubernetes). Helm работает так же — он не зависит от того, кто управляет кластером. Отличие в том, что многие дополнения (контроллеры, агенты) провайдер предлагает ставить своими средствами, и тогда важно не поставить то же самое чартом второй раз. Запуском не проверялось.
Что выбрать. Helm оправдан там, где есть параметризация и чужие приложения.
Если манифесты не параметризуются, а просто различаются в двух-трёх местах, шаблонизатор
может оказаться лишним — об этом весь следующий урок про Kustomize. Правило, которое
переносится в любую среду: значения окружения живут в файле в репозитории, а не
в команде; всё, что передано --set по ходу, существует только в памяти того, кто
это набрал.
4. Практика на занятии (30 минут)
Опыты — в lab-helm.sh, чарт —
в chart/, файл значений окружения —
values-prod.yaml.
Курс проходят самостоятельно, поэтому каждый шаг говорит, что ввести, зачем, что должно получиться и что делать при неудаче.
Стенд — kind, один узел (
kindest/node:v1.37.0), образ приложенияcourse-k8s-app:1. Первый вызов любого режима сам поднимает кластер и грузит в него образ (kind load docker-image) — это самая долгая часть первого шага. Запускайте режимы сKEEP=1, чтобы кластер оставался между шагами, а не пересоздавался на каждую команду.KUBECONFIGиHELM_*_HOMEлаборатория уводит во временный каталог — ваши настройки Helm и список репозиториев не затрагиваются. Уборка — последним шагом, режимомclean.
Шаг 1 (5 минут). Чарт и шаблон.
- Что ввести:
cd blocks/14-kubernetes-operations/examples/14.01-helm
KEEP=1 bash lab-helm.sh chart
- Зачем: увидеть, из чего состоит чарт, и убедиться, что шаблон превращается в манифест без обращения к кластеру.
- Ожидаемый результат: команда поднимет kind-кластер (первый запуск — дольше
остальных, дальше он остаётся благодаря
KEEP=1) и напечатает состав заготовкиhelm createрядом с нашим маленьким чартом —Chart.yaml,values.yaml,templates/*.yaml,_helpers.tpl— и две разные версии вChart.yaml:versionчарта иappVersionприложения. В конце — выводhelm template: два объекта (Service,Deployment) с именемweb-course-appиreplicas: 2. - Если не так: сообщение
сборка образа не удаласьиликластер не созданзначит, что не запущен Docker (проверьтеdocker ps); первый запуск ещё и качает образ узлаkindest/node:v1.37.0, это может занять несколько минут. - Ответьте: почему
helm templateработает без кластера и что из этого следует?
Шаг 2 (8 минут). Values и главная ловушка.
- Что ввести:
KEEP=1 bash lab-helm.sh values
- Зачем: увидеть приоритет источников values и главную ловушку урока — значения
не сохраняются между вызовами
helm upgrade. - Ожидаемый результат: сначала таблица четырёх способов задать одно и то же
значение (чарт слабее
-f,-fслабее--set); затемinstall --set replicaCount=3 --set appVersion=v1даётreplicas=3, а следующийupgradeтолько с--set appVersion=v2возвращаетreplicas=2— число реплик откатилось к значению чарта, хотя его никто не трогал. Прежде чем читать эту строку вывода, предскажите сами, чему будет равноreplicas. Дальше —--reuse-valuesи-f values-prod.yamlвозвращают три реплики двумя разными способами. - Если не так: если таблица или ловушка не совпадают с описанием из теории
(3.2) — с прошлого прогона остался чужой релиз; выполните
bash lab-helm.sh cleanи повторите режим заново. - Ответьте: почему
helm upgrade— это не «изменить одно поле», а «применить чарт с теми значениями, что переданы сейчас»?
Шаг 3 (7 минут). Состояние релиза и ревизии.
- Что ввести:
KEEP=1 bash lab-helm.sh release
KEEP=1 bash lab-helm.sh revisions
- Зачем: найти, где Helm хранит состояние релиза, и убедиться, что откат создаёт новую ревизию, а не возвращает старую.
- Ожидаемый результат: режим
releaseпокажет Secretsh.helm.release.v1.web.v1типаhelm.sh/release.v1с меткойstatus=deployed, разницу междуhelm get values(только переопределённое) и--all(итоговые значения), и предупреждение про колонкиhelm list— их не разбирать в скриптах, только-o json. Режимrevisionsпокажет три ревизии вhelm history, затемhelm rollback web 1создаст четвёртую ревизию с описаниемRollback to 1, а не вернёт первую. - Если не так: режим сам пересоздаёт релиз с нуля (
wipe) перед измерением, поэтому чужое состояние из прошлых шагов ему не мешает; повторный запуск безопасен. - Ответьте: чем ревизия релиза отличается от ревизии Deployment и может ли одна вырасти без другой?
Шаг 4 (7 минут). Дрейф и server-side apply.
- Что ввести:
KEEP=1 bash lab-helm.sh drift
- Зачем: убедиться, что Helm 4 применяет объекты через server-side apply, и увидеть, что из этого следует при ручной правке кластера. Ключевой режим урока.
- Ожидаемый результат: сначала
kubectl get deploy --show-managed-fieldsпокажет менеджераhelmс операциейApply. Затемkubectl scale --replicas=5вручную, и обычныйhelm upgradeупадёт с кодом 1 и сообщениемconflict with "kubectl" with subresource "scale" using apps/v1: .spec.replicas, а релиз перейдёт в статусfailed.--forceне сработает (cannot use server-side apply and force replace together), а--force-conflictsпройдёт с кодом 0. В конце — контрольный опыт с--server-side=false: тот же дрейф правится молча, кодом 0, без единого сообщения о конфликте. - Если не так: если
helm upgradeне упал (код 0) — опыт не показал того, ради чего делался, лаба сама печатает это предупреждение; проверьте версию (helm version) — должна быть 4.x. - Ответьте: что произошло, какой механизм Kubernetes за этим стоит и какие два выхода из конфликта у вас есть?
Шаг 5 (3 минуты). Проверка и уборка.
- Что ввести:
KEEP=1 bash lab-helm.sh verify
bash lab-helm.sh clean
- Зачем: увидеть, что четыре способа «проверить перед установкой» не равноценны, и убрать за собой стенд.
- Ожидаемый результат: таблица из пяти строк.
helm lint,helm template,helm install --dry-runи дажеhelm install --dry-run=serverвернут код 0 на опечатке в имени поля (imagePullPolicyy) — ни один её не поймает. Толькоhelm template | kubectl apply --dry-run=server -f -вернёт код 1 с текстомunknown field. Послеclean— ноль кластеров с именемlab1301и ноль контейнеров с этим префиксом. - Если не так: если код 1 не появился ни в одной строке — опечатка не внеслась
в шаблон; лаба сама прерывается с сообщением
опечатка не внеслась — опыт недействителен, проверьте права на запись вchart/templates/. - Ответьте: найдите строку, где код 0 означает не «всё хорошо», а «эта проверка такого не видит».
Режимы hooks и deps на занятие не выносятся — они в домашней работе.
Что обсудить в конце занятия. Инженер выкатил релиз командой
helm upgrade app ./chart --set image.tag=1.4.2, всё поднялось. Через неделю другой
инженер выкатил helm upgrade app ./chart --set replicaCount=6. Что стало с версией
образа и почему? Как надо было?
5. Домашняя работа (1–2 часа)
Задание. Собрать чарт для своего приложения и доказать обратимость выката.
Часть 1. Свой чарт. Возьмите любое приложение (подойдёт учебное) и напишите чарт
с нуля — без helm create, чтобы в нём не было лишнего. Обязательно: Deployment,
Service, _helpers.tpl с именованным шаблоном имени, values.yaml минимум с пятью
параметрами. Проверьте helm lint и отрисуйте helm template.
Часть 2. Два окружения одним чартом. Сделайте values-dev.yaml и values-prod.yaml,
отличающиеся не меньше чем тремя значениями. Покажите выводом helm template, что
из одного чарта получаются два разных набора манифестов. Ответьте: что из ваших значений
нельзя держать в этих файлах и почему (13.08).
Часть 3. Хуки и провал миграции. Добавьте в чарт Job на pre-upgrade
(пример) и прогоните режим:
KEEP=1 bash lab-helm.sh hooks
Зафиксируйте: что происходит с приложением, когда миграция падает; чем отличается
поведение с --atomic; что остаётся в кластере после uninstall и почему.
Затем измените hook-delete-policy так, чтобы остатков не было, и покажите, что помогло.
Часть 4. Дрейф своими руками. Поставьте свой чарт, измените что-нибудь в кластере
через kubectl, попробуйте helm upgrade. Опишите: какой код возврата, что в сообщении,
какое поле конфликтует и два способа выйти из положения. Затем повторите то же
с --server-side=false и объясните разницу.
Часть 5. Проверка перед выкатом. Внесите в свой чарт ошибку, которую не видит
helm lint, и постройте проверку, которая её ловит. Приведите обе команды и коды
возврата. Ответьте: почему helm install --dry-run=server на эту ошибку не срабатывает,
и что вы поставите в пайплайн (09.07).
Часть 6. Зависимости (по желанию). Прогоните режим deps и объясните, зачем нужен
Chart.lock и что делает condition.
Результаты — в карточку
homework/helm-workbook.md.
Критерии приёмки.
- свой чарт написан без
helm create,helm lintпроходит, приведён выводhelm template; - два файла значений дают разные манифесты — показано выводом; сказано, чего в них держать нельзя;
- поведение при провале миграции зафиксировано, разница с
--atomicобъяснена, остатки хука убраны сменой политики и это подтверждено выводом; - дрейф воспроизведён: приведены код возврата, текст конфликта, конфликтующее поле и два способа выхода;
- найдена ошибка, которую
helm lintне видит, и команда, которая её ловит — с кодами возврата обеих; - в ответах нет утверждений «должно работать»: каждое подтверждено выводом команды.
Файлы для работы: blocks/14-kubernetes-operations/examples/14.01-helm/
6. Частые ошибки и подводные камни
Выкат через --set без файла значений. Симптом: после чужого upgrade у сервиса
съехало число реплик или вернулся старый образ. Причина: значения не сохраняются между
командами — helm upgrade применяет чарт с тем, что передано сейчас. Что делать:
значения окружения держать в файле в git и выкатывать -f; --reuse-values — только
как разовая мера, потому что тащит состояние, которого нет в репозитории.
Правка кластера руками при Helm 4. Симптом: helm upgrade падает с
conflict with "kubectl" … .spec.replicas, релиз уходит в failed. Причина: Helm 4
применяет объекты через server-side apply, и поле принадлежит другому менеджеру (13.03).
Что делать: --force-conflicts, если поле действительно ваше; и не править то, чем
управляет Helm, — иначе следующий выкат встанет в неподходящий момент.
Ждут, что --force решит конфликт. Симптом: invalid operation: cannot use server-side apply and force replace together. Причина: --force (он же
--force-replace) — про замену объекта целиком, это другой механизм. Что делать:
при server-side apply нужен --force-conflicts.
Доверяют helm install --dry-run=server. Симптом: проверка прошла, установка упала.
Причина: измерено — опечатку в имени поля этот пробный прогон не видит, хотя
kubectl apply --dry-run=server на том же манифесте видит. Что делать: в пайплайн
ставить helm template … | kubectl apply --dry-run=server -f -.
Считают, что helm diff показывает дрейф. Симптом: в кластере руками изменили
реплики, helm diff upgrade печатает пустоту. Причина: он сравнивает новый чарт
с сохранённым релизом, а не с кластером. Что делать: --dry-run=server для сравнения
с кластером; для поиска дрейфа вообще — инструменты GitOps (14.10).
Ожидают, что откат вернёт прежнюю ревизию. Симптом: история релиза растёт после
каждого отката, и в ней не разобраться. Причина: helm rollback создаёт новую ревизию
с описанием Rollback to N. Что делать: помнить, что это временная мера, и сразу
приводить в порядок то, из чего собирается релиз (тот же вывод, что в 13.05).
Неудачный выкат оставляют в состоянии failed. Симптом: следующий upgrade
начинается из непонятного состояния, часть объектов новая, часть старая. Причина:
без --atomic Helm не откатывает то, что успел применить. Что делать: --atomic
в пайплайне; помнить, что код возврата всё равно 1 — успех надо проверять по коду,
а не по статусу релиза.
Забывают про остатки хуков. Симптом: после uninstall в namespace остались Job
и поды от миграций. Причина: hook-delete-policy: before-hook-creation удаляет объект
перед следующим запуском, а не после успеха. Что делать: hook-succeeded для того,
что не нужно хранить, и уборка старых Job по расписанию (13.12).
Секреты в values. Симптом: пароль виден любому, кто может читать секреты namespace. Причина: состояние релиза — обычный Secret, и values лежат в нём целиком. Что делать: то же, что в 13.08 и 07.03: секреты передавать отдельно, а в чарте ссылаться на имя существующего Secret.
7. Проверка усвоения
- Чем
versionотличается отappVersionвChart.yaml? Приведите случай, когда меняется одно и не меняется другое. - Значение задано в
values.yamlчарта, в файле-fи в--set. Какое победит? Что будет, если передать два файла-f? - Вы поставили релиз с
--set replicaCount=5, затем сделалиhelm upgradeс одним--set image.tag=2.0. Сколько будет реплик и почему? - Где Helm хранит состояние релиза и какие два практических следствия из этого вытекают?
- Чем ревизия релиза отличается от ревизии Deployment? Может ли одна вырасти без другой?
helm upgradeвернулconflict with "kubectl" … .spec.replicas. Что произошло, какой механизм Kubernetes за этим стоит и какие два выхода у вас есть?helm lint,helm templateиhelm install --dry-run=serverвернули 0, а установка упала. Как такое возможно и какую проверку надо было выполнить?- Миграция на
pre-upgradeупала. Что стало с приложением? Что изменится, если добавить--atomic, и каким будет код возврата?
8. Материалы
- Helm Docs — Charts — устройство чарта:
Chart.yaml, структура каталогов, зависимости,conditionиtags. Основной документ, с которого стоит начинать. - Values Files — как
устроены values и в каком порядке они переопределяются; читать до первого
--setв пайплайне. - helm upgrade — справочник — все флаги,
включая
--server-side(по умолчаниюauto),--force-conflicts,--take-ownership,--atomic,--history-max. Именно здесь видно, что в Helm 4 применение серверное. - Chart Hooks — список событий,
hook-weightи политики удаления; раздел проhook-delete-policyобъясняет остатки, которые мы намерили. - Helm 4 release notes — перечень изменений относительно Helm 3; полезно, когда натыкаетесь на совет из статьи, который «почему-то не работает».
- helm-diff — плагин для просмотра изменений до применения; в README же оговорены его границы (сравнение с сохранённым релизом, а не с кластером).
← Предыдущий: 13.14. Отладка в кластере: события, логи, типовые сбои · Блок 14 · Следующий: 14.02. Kustomize, наложения и выбор между Helm и Kustomize →
Материалы для практики
Скрипты, шпаргалки и заготовки к заданиям урока. Текст урока — на этой странице.
-
Материалы к уроку 14.01 «Helm чарты, values, релизы».zip