Паттерны и best practices
Сводим опыт в набор правил, отличающих надёжный прод-чарт от хрупкого.
Хороший чарт предсказуем, безопасен по умолчанию и воспроизводим. Большинство практик сводятся к двум принципам: фиксируй версии и не доверяй неявному поведению.
Версионирование по SemVer
Поднимайте version чарта при любой правке шаблонов или дефолтов, даже если код приложения не менялся: PATCH — мелкие правки, MINOR — новые параметры с обратной совместимостью, MAJOR — несовместимые изменения (переименование values, удаление параметра). appVersion двигайте отдельно — при релизе кода. Эта дисциплина даёт честный changelog чарта.
Чтобы понять разницу version и appVersion на примере: вы выпустили версию приложения 2.4.1 и упаковали её чартом 1.2.0. Через неделю вы заметили, что в шаблоне забыли пробросить probe — код приложения не менялся, но чарт исправлен. Тогда appVersion остаётся 2.4.1, а version чарта растёт до 1.2.1. Потребитель чарта по одному номеру видит, что упаковка изменилась, и может осознанно решить, обновляться ли. Если же смешать эти оси и двигать только одну версию на двоих, история чарта начнёт врать: невозможно отличить «починили шаблон» от «вышла новая версия кода».
Ключевой вопрос совместимости при MINOR — не сломаются ли существующие установки. Новый параметр обязан иметь дефолт, воспроизводящий прежнее поведение: тот, кто обновил чарт, но не трогал свои values, должен получить ровно тот же результат, что и раньше. Если новый параметр меняет поведение по умолчанию — это уже MAJOR, как бы мала ни была правка по объёму кода. Дисциплина SemVer измеряет не размер диффа, а влияние на потребителя.
Иммутабельные теги образов
Никогда не используйте latest или мутирующие теги (stable, prod). Тег должен быть иммутабельным: git-SHA или семантическая версия. Иначе helm rollback вернёт манифест со старым тегом latest, который сегодня указывает уже на другой образ — откат окажется фиктивным.
Стандартные лейблы
Размечайте все ресурсы рекомендованными лейблами Kubernetes — по ним работают kubectl-селекторы, дашборды и сетевые политики:
labels:
app.kubernetes.io/name: webapp
app.kubernetes.io/instance: web
app.kubernetes.io/version: "2.4.1"
app.kubernetes.io/managed-by: Helm
helm.sh/chart: webapp-1.2.0
Выносите их в _helpers.tpl (урок про именованные шаблоны), чтобы не дублировать.
Безопасные дефолты
replicaCount: 1, скромные ресурсы — пользователь сам поднимет под нагрузку.- Ingress, LoadBalancer, отладочные эндпоинты — выключены по умолчанию.
- Никаких реальных секретов в дефолтных values — только плейсхолдеры.
- Задавайте
resources.requests— иначе планировщик не сможет адекватно разместить поды.
Принцип за всем списком один: дефолты должны быть безопасны при невнимательной установке. Человек, запустивший helm install без единого флага, не должен случайно выставить приложение в интернет, отдать наружу debug-эндпоинт или поднять десяток реплик, которыми не управлял. Чарт по умолчанию обязан давать минимальную работоспособную конфигурацию, а всё рискованное и дорогое — включаться явно. Это та же логика, что и в безопасных настройках любого софта: небезопасное состояние требует сознательного действия, а не наоборот.
Работа с секретами
Отдельная больная тема — пароли, токены и ключи. Класть их в открытом виде в values.yaml или, тем более, коммитить в git нельзя: репозиторий чарта и история релизов Helm не предназначены для хранения секретов. Дефолтные values держат только плейсхолдеры (changeme, пустую строку), а реальные значения приходят отдельным каналом: из менеджера секретов (Vault, облачный Secrets Manager), через оператор External Secrets, который материализует Kubernetes Secret из внешнего хранилища, либо через шифрование values на месте (sops). Сам чарт лишь ссылается на секрет по имени, а не содержит его. Так компрометация git-репозитория не означает утечку паролей, а ротация ключа не требует нового релиза чарта.
Структура и читаемость
- Один манифест — один файл в
templates/с говорящим именем (deployment.yaml,service.yaml). - Группируйте и комментируйте
values.yaml— это документация чарта. - Прикладывайте
values.schema.jsonдля валидации ввода. - Заполняйте
NOTES.txt— пользователь после install должен знать, как достучаться до приложения.
Здоровье приложения
Закладывайте в шаблон readinessProbe и livenessProbe (настраиваемые через values). Без readiness --wait не сможет понять, что под действительно готов, и деплой «зелёный», когда приложение ещё не отвечает.
Различайте две пробы по их назначению, иначе легко выстрелить себе в ногу. readinessProbe отвечает на вопрос «можно ли слать трафик прямо сейчас» — пока она красная, под исключён из сервиса, но не перезапускается; это нормальное состояние во время прогрева или временной недоступности зависимости. livenessProbe отвечает на вопрос «жив ли процесс вообще» — её провал ведёт к перезапуску пода. Частая ошибка — повесить liveness на эндпоинт, который ходит в базу: тогда кратковременная недоступность БД вызовет каскадные перезапуски всех подов и превратит мелкий сбой в полную аварию. Liveness должна проверять только сам процесс, readiness — готовность обслуживать запросы с учётом зависимостей.
Воспроизводимость зависимостей
Коммитьте Chart.lock, фиксируйте версии subchart-ов точными значениями для прода, прогоняйте helm dependency update в CI. «Плавающие» x.x.x хороши для разработки, но в релизе фиксируйте.
Почему это работает: принцип наименьшего сюрприза
Под капотом все эти практики обслуживают одну цель — убрать недетерминизм. Helm детерминирован сам по себе (одинаковый ввод → одинаковые манифесты), но ввод легко сделать недетерминированным: плавающий тег образа, плавающая версия subchart, неявные дефолты, отсутствие probe. Каждая практика выше закрывает один источник «сюрприза»: фиксированный тег → честный rollback; SemVer → предсказуемые апгрейды; безопасные дефолты → нет случайного внешнего доступа; probe → честный --wait. Прод-чарт — это чарт, в котором не осталось скрытых движущихся частей.
Частые ошибки
- Не поднимать
versionчарта. История чарта врёт, потребители не видят, что изменилось. - Опасные дефолты. Включённый ingress «из коробки» открывает приложение наружу неожиданно.
- Нет probe.
--waitбесполезен, деплой считается успешным до готовности приложения.
Итог
- Фиксируйте версии: SemVer чарта, иммутабельные теги образов, точные версии subchart-ов и
Chart.lock. - Дефолты безопасны и скромны; внешний доступ выключен; стандартные лейблы и probe — обязательны.
- Все практики служат детерминизму: прод-чарт не имеет скрытых движущихся частей.