Зависимости чарта и subcharts
Приложению часто нужна база или кеш. Вместо отдельной установки их подключают как зависимости чарта.
Subchart — это другой чарт, объявленный в
dependenciesродителя. Helm устанавливает родителя и его subchart-ы как единый релиз.
Зачем подключать чужие чарты, а не ставить их отдельно
Можно установить PostgreSQL отдельным релизом, а приложение — своим, и связать их вручную через адреса сервисов. Так делают, и это нормально. Но как только число компонентов растёт, ручная связка превращается в проблему: их надо устанавливать в правильном порядке, обновлять согласованно, откатывать вместе, передавать друг другу пароли и хосты. Subchart-ы решают это композицией: вы описываете «моё приложение состоит из веб-сервиса, базы и кеша» в одном чарте, и весь набор живёт как единое целое — один helm install, один helm upgrade, один helm rollback, одна точка истины для значений. Это особенно ценно для эфемерных окружений: чтобы поднять полную копию системы под pull request, достаточно одной команды.
У этого удобства есть цена, о которой стоит думать заранее. Чужой subchart (тот же bitnami/postgresql) — это код, который вы не писали и не контролируете: у него своя политика версионирования, свои значения по умолчанию, свои представления о безопасности и ресурсах. Подключив его, вы берёте на себя ответственность следить за его обновлениями (там бывают CVE) и понимать его values.yaml достаточно, чтобы настроить под себя. Для продакшена многие команды сознательно не используют встроенный stateful-subchart базы данных, предпочитая управляемый сервис (RDS, Cloud SQL), и оставляют subchart только для dev — ровно тот сценарий, ради которого существует condition.
Объявление зависимости
# Chart.yaml
dependencies:
- name: postgresql
version: "13.2.24"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: "18.x.x"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
tags:
- cache
Загрузка зависимостей
Объявить мало — нужно скачать чарты в папку charts/:
helm dependency update ./webapp # скачать по Chart.yaml -> charts/*.tgz
helm dependency list ./webapp # показать статус зависимостей
Это создаёт файл Chart.lock с зафиксированными версиями — аналог package-lock.json. Коммитьте его для воспроизводимости.
Различие между helm dependency update и helm dependency build стоит запомнить, потому что в CI путают именно его. update идёт в репозитории, разрешает диапазоны версий вроде 18.x.x в конкретную последнюю подходящую версию и перезаписывает Chart.lock. build, наоборот, читает уже существующий Chart.lock и скачивает ровно те версии, что в нём зафиксированы, ничего не разрешая заново. Правило простое: на машине разработчика, когда вы осознанно поднимаете версию зависимости, — update; в пайплайне сборки, где нужна воспроизводимость один-в-один, — build по закоммиченному локу. Если в CI звать update, вы рискуете молча подтянуть новую минорную версию subchart-а, которую никто не тестировал.
Передача values в subchart
Значения subchart-а живут в родительском values.yaml под ключом с именем subchart-а:
# values.yaml родителя
postgresql: # всё внутри уходит в subchart postgresql
enabled: true
auth:
username: app
database: webapp
primary:
persistence:
size: 8Gi
redis:
enabled: false # выключен через condition
Ключ postgresql совпадает с name зависимости — так Helm понимает, кому адресованы значения.
condition: включить/выключить зависимость
condition: postgresql.enabled означает: subchart разворачивается, только если .Values.postgresql.enabled истинно. Это позволяет в проде использовать внешнюю управляемую БД (выключив встроенный postgresql), а в dev — встроенный:
# values/prod.yaml — внешняя БД, встроенную не поднимаем
postgresql:
enabled: false
externalDatabase:
host: prod-db.rds.amazonaws.com
tags: групповое управление
Если несколько зависимостей помечены тегом (например, cache), их можно включать/выключать пачкой:
tags:
cache: false # выключит все зависимости с тегом cache
Глобальные значения для всех subchart
Секция global в родительских values видна всем subchart-ам — удобно для общих параметров (домен, imagePullSecrets):
global:
imageRegistry: registry.example.com
storageClass: fast-ssd
Важно понимать, чем global отличается от обычной передачи values по ключу-имени. Значения под ключом postgresql видит только subchart postgresql; значения под global видят все — и родитель, и каждый subchart, причём по одному и тому же пути .Values.global.*. Это единственный штатный канал, по которому родитель может «сверху» продиктовать общий параметр всем потомкам сразу. Но именно поэтому global легко превратить в свалку: туда тянет сложить всё подряд, и тогда непонятно, кто на что влияет. Здравое правило — держать в global только по-настоящему сквозные вещи: registry образов, storageClass, общий домен, секреты вытягивания образов. Всё, что специфично для одного компонента, должно жить под его собственным ключом.
Алиасы и переопределение значений зависимостей
Иногда один и тот же subchart нужен дважды — например, два независимых Redis: один под кеш, другой под очередь. Поле alias в зависимости даёт subchart-у новое имя, под которым он и рендерится, и принимает values. Тогда в Chart.yaml будут две записи с одним name: redis, но разными alias: redis-cache и alias: redis-queue, а в values появятся два независимых блока redis-cache: и redis-queue:. Это снимает конфликт имён, который иначе сделал бы двойное подключение невозможным. Рядом стоит упомянуть import-values — механизм, позволяющий «поднять» часть значений subchart-а в родителя, чтобы пользователь чарта не лез в детали вложенной структуры; в простых чартах он не нужен, но в больших платформенных — экономит много путаницы.
Как зависимости работают под капотом
При рендере Helm строит дерево чартов: родитель + subchart-ы (и их subchart-ы рекурсивно). Каждый subchart рендерится в своём контексте: его .Values — это поддерево из родителя под ключом-именем плюс global. Все отрендеренные манифесты родителя и subchart-ов собираются в один релиз и применяются вместе; ревизия тоже общая. Поэтому helm upgrade родителя обновляет и subchart-ы, а helm rollback откатывает всё дерево разом. Chart.lock фиксирует точные версии скачанных subchart-ов, чтобы сборка была воспроизводимой между машинами и временем.
Частые ошибки
- Забыть
helm dependency update. Объявил зависимость в Chart.yaml, ноcharts/пуст — install падает с «found in Chart.yaml, but missing in charts/». - Неверный ключ values. Значения под ключом, не совпадающим с
namesubchart-а, до него не дойдут. - Не коммитить
Chart.lock. Версии subchart-ов «уплывут» у коллеги.
Итог
- Зависимости объявляют в
Chart.yaml, скачивают черезhelm dependency update(фиксируется вChart.lock). - Values subchart-а — под ключом с его именем;
condition/tagsвключают и выключают зависимости. - Родитель и subchart-ы — единый релиз: общий upgrade/rollback;
globalделит значения между всеми.