# Helm charts - пакетный менеджер для Kubernetes _Контейнеры (бонус) · LinuxLab Knowledge Base_ **TL;DR:** Helm - пакетный менеджер k8s. Chart - папка с Chart.yaml, values.yaml и templates/ (Go-templates над YAML). Releases хранятся в Secret namespace'а; upgrade/rollback атомарны. Альтернатива - kustomize (без templating, патчи). ## Зачем Helm Развернуть приложение в k8s, это десяток YAML: Deployment, Service, Ingress, ConfigMap, Secret, ServiceAccount, RBAC, HPA, PDB. Развернуть **то же самое в dev / staging / prod** с разными значениями, копипаст и поломки. Helm решает три задачи: 1. **Шаблонизация**, values.yaml + Go-templates → готовые YAML 2. **Релизы**, install/upgrade/rollback с версионированной историей 3. **Дистрибуция**, chart как артефакт (tar.gz в OCI registry или старом chartmuseum) В 2026, фактический стандарт для пакетирования open-source приложений в k8s. nginx, postgres, redis, prometheus, grafana, cert-manager, у всех есть official chart. ## Структура chart ``` mychart/ ├── Chart.yaml # metadata: name, version, appVersion ├── values.yaml # default-значения переменных ├── values.schema.json # опционально: JSON-schema для values ├── templates/ │ ├── _helpers.tpl # переиспользуемые шаблоны │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── configmap.yaml │ └── NOTES.txt # печатается после install ├── charts/ # вложенные dependency-charts └── crds/ # CRD'ы устанавливаются ДО templates ``` ## Chart.yaml, metadata ```yaml apiVersion: v2 # v2 = Helm 3 name: my-app description: My production app type: application # application | library version: 1.4.2 # version самого chart (SemVer) appVersion: "2.6.0" # version приложения внутри dependencies: - name: postgresql version: "12.x.x" repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled ``` Различай: **`version`** меняется при изменениях chart (даже если код приложения тот же), **`appVersion`**, версия приложения. ## Templates, Go templates над YAML Файлы в `templates/` рендерятся через Go-template engine. Доступны: - `.Values`, содержимое values.yaml (плюс overrides из CLI) - `.Release`, `.Release.Name`, `.Release.Namespace`, `.Release.Revision` - `.Chart`, содержимое Chart.yaml - `.Capabilities`, версия k8s, доступные API - `.Files`, статичные файлы chart'а (для configMap) ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "my-app.fullname" . }} labels: {{- include "my-app.labels" . | nindent 4 }} spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: app image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" {{- with .Values.resources }} resources: {{- toYaml . | nindent 12 }} {{- end }} env: {{- range $k, $v := .Values.env }} - name: {{ $k }} value: {{ $v | quote }} {{- end }} ``` Стандартные правила: - `{{- ... -}}`, убрать whitespace до/после - `nindent N`, отступ N пробелов с newline'ом перед - `toYaml`, серилизовать map/list в YAML - `default X .Values.foo`, fallback если значение пустое - `required "foo нужен" .Values.foo`, ошибка если не задано ## Helpers (`_helpers.tpl`) Переиспользуемые шаблоны: ```yaml {{/* labels стандартные k8s */}} {{- define "my-app.labels" -}} app.kubernetes.io/name: {{ .Chart.Name }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} {{- end }} ``` Файлы начинающиеся с `_` не рендерятся как k8s-объекты, только определяют helper'ы. ## Lifecycle команд ```bash # Локальная отладка - что выйдет, не применяя helm template my-release ./mychart -f values-prod.yaml # Установка (создаёт release в namespace'е) helm install my-release ./mychart -n production --create-namespace # Обновление (с историей версий) helm upgrade my-release ./mychart -f values-prod.yaml # Откат на предыдущую ревизию helm rollback my-release # на N-1 helm rollback my-release 3 # на ревизию 3 # История релизов helm history my-release # Список всех релизов helm list -A # Удалить helm uninstall my-release ``` Каждый release хранится как **Secret** типа `helm.sh/release.v1` в namespace'е. Содержит сжатый JSON со всеми манифестами и values. Это база для rollback'а. ## values.yaml, overrides ```yaml # values.yaml (default) replicaCount: 1 image: repository: nginx tag: "" # пусто → fallback на Chart.AppVersion pullPolicy: IfNotPresent resources: requests: { cpu: 100m, memory: 128Mi } ingress: enabled: false ``` ```bash # Переопределить из CLI или из второго values-файла helm install my-release ./mychart \ -f values.yaml -f values-prod.yaml \ --set replicaCount=3 \ --set image.tag=v2.6.0 \ --set-string env.DEBUG=false # принудительно строкой ``` Порядок: default values.yaml → -f files (по порядку) → --set. Поздние overridят ранние. ## Helm vs kustomize, когда что | Признак | Helm | Kustomize | |---------|------|-----------| | Подход | templating (Go-templates) | overlays (патчи) | | Версионирование релиза | да, в Secret | нет (нативно) | | Установка | `helm install` | `kubectl apply -k ./` | | Кривая обучения | средняя (templating язык) | пологая (только YAML + патчи) | | Дистрибуция | chart-репо, OCI registry | git-репо | | Conditional logic | сильная (`if`/`else`/`range`) | слабая (только overlays) | | Hooks (pre/post-install) | да | нет | | Когда выбирать | дистрибуция чужих приложений, сложная логика | свои деплои с парой окружений | Часто комбинируют: helm для общедоступных chart'ов (postgres-operator, ingress-nginx), kustomize для своих app-deployments. Или **Helmfile** / **ArgoCD** как orchestrator поверх обоих. ## Hooks Special-аннотации в манифестах для запуска до/после lifecycle: ```yaml apiVersion: batch/v1 kind: Job metadata: name: db-migration annotations: "helm.sh/hook": pre-upgrade,pre-install "helm.sh/hook-weight": "-5" "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded ``` Помогает запустить миграции БД до апдейта приложения. Минус: hook-Jobs не учитываются в release-истории, при rollback не откатятся. ## Dependencies Chart может зависеть от других chart'ов: ```yaml # Chart.yaml dependencies: - name: postgresql version: "12.x.x" repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled # включается через values alias: db # обращаться через .Values.db ``` ```bash helm dependency update # скачивает в charts/ helm dependency build # из Chart.lock ``` Subchart values переопределяются через корневой values.yaml: ```yaml postgresql: # имя subchart'а auth: database: myapp username: myapp ``` ## OCI registries, Helm 3.8+ Chart можно публиковать в OCI registry (Docker Hub, ECR, GHCR): ```bash helm package ./mychart # → mychart-1.4.2.tgz helm push mychart-1.4.2.tgz oci://ghcr.io/me/charts helm install my-rel oci://ghcr.io/me/charts/mychart --version 1.4.2 ``` Бонус: можно подписывать через [[image-signing-cosign|cosign]] как обычные образы. ## Когда что-то пошло не так - **`Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress`**, упал предыдущий upgrade. `helm history`, потом `helm rollback` или удалить «pending» release-secret вручную. - **`unable to recognize "": no matches for kind "Foo"`**, CRD не установлен. Положи в `crds/` или установи отдельно `--skip-crds`. - **values рендерятся не так как ожидаешь**, `helm template my-rel ./chart -f values.yaml` локально, посмотри YAML до apply. - **`{{ .Values.foo.bar }}` падает с nil pointer**, нет defaults в values.yaml. Используй `(.Values.foo).bar` или `default`. - **Hook job висит**, нет `hook-delete-policy`, остаётся как pod после успеха. Добавить `hook-succeeded`. - **release есть, объекты исчезли**, кто-то прошёлся `kubectl delete` мимо Helm. `helm upgrade --force` пересоздаст. Воспитательная беседа с командой о mutability через Helm. - **Secrets bloat**, много upgrade'ов, много Secret'ов в namespace'е. `--history-max 10` ограничивает количество. - **`Error: rendered manifests contain a resource that already exists`**, был создан вручную тот же объект. Удалить старый или `helm install --take-ownership` (Helm 3.14+). ## Команды ```bash helm install my-rel ./mychart -n prod --create-namespace -f values-prod.yaml ``` Установка release с values-файлом и созданием namespace при отсутствии ```bash helm template my-rel ./mychart -f values.yaml ``` Локально отрендерить шаблоны без apply - debug для template-ошибок ```bash helm upgrade --install my-rel ./mychart -f values.yaml --atomic --timeout 5m ``` Idempotent install/upgrade с откатом при неуспехе - паттерн для CI/CD ```bash helm rollback my-rel 3 ``` Откат release на конкретную ревизию из истории ```bash helm history my-rel ``` История ревизий release с таймстампами и chart-version ```bash helm dependency update ./mychart ``` Скачать subchart'ы из dependencies в charts/ и обновить Chart.lock ```bash helm lint ./mychart ``` Проверка на типичные ошибки в шаблонах и Chart.yaml до релиза ## См. также - [Kubernetes pod lifecycle - от Pending до Terminated](/kb/kubernetes-pod-lifecycle.md) - [Kubernetes Service и Ingress - сетевая публикация подов](/kb/kubernetes-services-and-ingress.md) - [Kubernetes storage - PV, PVC, StorageClass, CSI](/kb/kubernetes-storage.md) - [bash-скрипты - основы и идиомы](/kb/bash-scripting.md) - [Cosign и подпись container images (sigstore)](/kb/image-signing-cosign.md)