Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 18.01 · 22 мин
Средний
HelmChartReleasepackage managerGo templatesHelm 3

Helm: что это и зачем

Когда у тебя один Deployment — kubectl apply -f deployment.yaml достаточно. Когда у тебя приложение из 20 YAML-файлов (Deployment, Service, Ingress, ConfigMap, Secret, ServiceAccount, RBAC, HPA, PDB, NetworkPolicy…) — и эти манифесты должны быть разные в dev, staging, prod — становится больно. Helm — это решение от Kubernetes community для упаковки, версионирования и установки таких “приложений” одной командой. Это apt / brew / npm мира Kubernetes.


Структура compose.yml: services, build, ports, volumes

Что такое Helm

Helm — package manager для Kubernetes. Его основная единица — Chart (пакет): директория с YAML-шаблонами и default-значениями, описывающая всё, что нужно для разворачивания приложения. Когда ты делаешь helm install, Helm:

  • Рендерит templates с подставленными values в plain YAML.
  • Отправляет результирующие manifests в apiserver через тот же протокол, что и kubectl apply.
  • Сохраняет метаданные релиза (имя, ревизия, rendered manifests, history) в виде Secret в том же namespace.

Это означает: Helm — это client-side инструмент. В кластере ничего особенного нет. Любой манифест, который применил Helm, можно увидеть через обычный kubectl get.

Helm: client-side архитектура
helm CLIКлиентский бинарь. Читает Chart с диска или из repo, рендерит Go templates с подставленными values, формирует список K8s manifests.
values + ChartChart — директория templates/. Values — YAML файл с конфигурацией (values.yaml + переопределения через -f и --set). Final values mergeятся по приоритету.
kube-apiserverHelm использует ту же kubeconfig что и kubectl. Через REST API создаёт/обновляет K8s resources. RBAC проверяется как обычно — Helm не имеет привилегий выше пользователя.
Release SecretПосле apply Helm сохраняет состояние релиза как Secret в namespace релиза: sh.helm.release.v1.<name>.v<revision>. Тип: helm.sh/release.v1. Внутри — gzip+base64 от JSON с rendered manifests и values.
K8s resourcesDeployment, Service, ConfigMap и т.д. — обычные K8s объекты. У них в labels/annotations стоит app.kubernetes.io/managed-by=Helm и release name, чтобы Helm потом смог их найти и удалить.
kubeletСоздаёт Pods по Deployment-у. Никакой разницы с обычным kubectl apply — Helm только рендерит и применяет, всё остальное делает Kubernetes контрол-плейн.

Helm 2 vs Helm 3: почему Tiller убрали

В Helm 2 (до 2019) была серверная часть — Tiller, Deployment с cluster-admin правами в kube-system. Helm CLI отправлял шаблоны Tiller-у, тот рендерил и применял. Проблем было много:

  • Security: Tiller с cluster-admin = эскалация привилегий. Любой, кто мог достучаться до Tiller (через port-forward или внутрикластерно) — получал admin на весь кластер.
  • RBAC bypass: RBAC проверял права Tiller, а не пользователя.
  • State management: история релизов хранилась в ConfigMaps в kube-system, конкурирующие helm-инстансы могли портить состояние.

Helm 3 (с 2019) — client-only:

  • Никакого Tiller, никаких серверных компонентов.
  • Helm использует ту же kubeconfig, что и kubectl — RBAC применяется к пользователю.
  • Релизы хранятся как Secrets в том же namespace, что и приложение (по умолчанию). Secret имя — sh.helm.release.v1.<release-name>.v<revision>.
  • Можно использовать --driver=configmap или --driver=sql для альтернативных backend-ов.
INFO

В 2026 году Helm 2 EOL уже несколько лет. Если видишь legacy-проект с Tiller — это первая вещь, которую нужно мигрировать. helm 2to3 convert — официальный плагин для миграции релизов.


Структура Chart

Chart — это директория с фиксированной структурой:

mychart/
├── Chart.yaml          # metadata: name, version, appVersion, dependencies
├── values.yaml         # default config values
├── values.schema.json  # JSON Schema для валидации values (опционально)
├── templates/          # YAML templates (Go templating)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── _helpers.tpl    # template helpers (define + include)
│   ├── NOTES.txt       # вывод после install (как использовать релиз)
│   └── tests/          # helm test — манифесты Pod-ов для smoke-tests
│       └── test-connection.yaml
├── charts/             # dependencies (subcharts), unpacked
├── crds/               # CustomResourceDefinitions, installed first
├── README.md
└── LICENSE

Ключевые файлы:

  • Chart.yaml — метаданные: name, version (SemVer Chart-а), appVersion (версия приложения, которое чартом упаковано), dependencies (список subcharts).
  • values.yaml — default-значения. Пользователь может переопределить через -f my-values.yaml или --set key=value.
  • templates/*.yaml — Go-шаблоны манифестов. На рендере становятся обычными K8s манифестами.
  • templates/_helpers.tpl — переиспользуемые шаблоны (как функции). Имя начинается с _ — Helm не пытается рендерить как K8s манифест.
  • crds/ — CRD устанавливаются до templates, и не удаляются при helm uninstall (специально, чтобы не сломать другие релизы).

Repository и Release: терминология

Три ключевых понятия:

  • Chart — пакет (директория или .tgz архив). Сам по себе ничего не делает.
  • Repository — HTTP-сервер с index.yaml, в котором перечислены доступные charts и ссылки на .tgz файлы. Примеры: Bitnami (https://charts.bitnami.com/bitnami), Artifact Hub (агрегатор). Repository — это просто статика на HTTP.
  • Release — инстанс установленного Chart-а в кластере. У одного Chart-а может быть много releases (например, два инстанса Redis: cache и queue).
# Repo: добавили source charts
helm repo add bitnami https://charts.bitnami.com/bitnami

# Chart: skachali, посмотрели, что внутри
helm pull bitnami/nginx --untar
ls nginx/

# Release: устанавливаем chart как named instance
helm install web bitnami/nginx --namespace web
helm install api bitnami/nginx --namespace api
# Это два разных Release-а одного и того же Chart-а.
Chart → Release: один Chart, много инстансов
RepositoryHTTP-сервер с index.yaml и .tgz файлами. Bitnami, Artifact Hub, GitHub Pages, любой S3 bucket с правильной структурой. Authentication: basic auth, OCI registry (с 2022 OCI стал стандартом — charts хранятся в Docker registry как OCI artifacts).
Chart (на диске)Локальная копия пакета. Helm кеширует в ~/.cache/helm/repository/. На диске — .tgz архив с Chart.yaml, values.yaml, templates/. Версионируется через Chart.version в Chart.yaml.
Release webhelm install web bitnami/nginx. Resources с release name web. Сохранён как Secret sh.helm.release.v1.web.v1 в namespace web. Имеет свою историю ревизий.
Release apihelm install api bitnami/nginx. Тот же chart, но другие values и namespace. Полностью независим от web — у каждого своя ревизия, свой rollback history.
Release cacheМожно установить третий релиз того же chart с другими values (например, --set image.tag=stable). Helm не препятствует — каждый release изолирован по имени и namespace.

Go templating: первый взгляд

Helm использует Go templates (пакет text/template) с расширениями из Sprig (string/math функции). В templates ты обращаешься к четырём встроенным объектам:

  • .Values — данные из values.yaml + переопределения от пользователя.
  • .Release.Release.Name, .Release.Namespace, .Release.Revision, .Release.IsInstall, .Release.IsUpgrade.
  • .Chart.Chart.Name, .Chart.Version, .Chart.AppVersion (из Chart.yaml).
  • .Capabilities.Capabilities.KubeVersion, .Capabilities.APIVersions.Has — для conditional на основе версии K8s.
  • .Files — доступ к файлам внутри Chart-а (для ConfigMap из файлов конфига).

Пример templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-web
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-web
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-web
    spec:
      containers:
        - name: nginx
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          ports:
            - containerPort: 80

И values.yaml:

replicaCount: 3
image:
  repository: nginx
  tag: "1.25"

После helm install web ./mychart Helm рендерит шаблон, подставляет значения, и применяет результат. Имя Deployment-а становится web-web, replicas=3, image=nginx:1.25.

WARNING

Helm-шаблоны до рендеринга не являются валидным YAML. Поэтому kubectl apply на сырых template-файлах не работает. И редакторы YAML могут орать на синтаксис. Используй helm template ./mychart --debug для дебага рендера до apply.


Release как Secret: что значит для управления

После helm install web ./mychart в кластере появляется Secret типа helm.sh/release.v1:

kubectl get secret -l owner=helm -n web
# NAME                             TYPE                 DATA   AGE
# sh.helm.release.v1.web.v1        helm.sh/release.v1   1      30s

Внутри (data[“release”] — gzip+base64+JSON):

  • Все rendered manifests, которые Helm применил.
  • Final values (после всех merges).
  • Метаданные: timestamp, статус (deployed/failed/pending-upgrade), пользователь (если есть).

При helm upgrade web ./mychart создаётся новый Secret sh.helm.release.v1.web.v2, старый остаётся (история ревизий — по умолчанию хранятся последние 10, контролируется --history-max). При helm rollback web 1 создаётся v3 со state из v1. При helm uninstall web --keep-history — статус релиза меняется на uninstalled, но Secrets остаются. Без --keep-history — Secrets удаляются.

DANGER

Если ты удалил Release Secret вручную (kubectl delete secret sh.helm.release.v1.web.v1) — Helm “забывает” про релиз, но manifests остаются в кластере. helm list его уже не видит. helm uninstall тоже не сможет — он же не знает, что чистить. Чинить: либо kubectl delete resources руками по labels, либо helm install web ... --replace (только в Helm 3).


Что отслеживает Helm, а что — нет

Это критически важный момент, который часто не понимают:

  • Helm не tracks отдельные K8s resources. Он не знает в моменте, сколько у тебя Pod-ов в Deployment. Он знает только rendered manifests из последнего apply.
  • helm uninstall удаляет всё, что было в последних rendered manifests через метку app.kubernetes.io/managed-by=Helm + ownership tracking.
  • Если ты вручную создал какой-то ресурс с тем же именем — Helm не возьмёт его в управление. helm upgrade может сломаться с conflict.
  • CRDs из crds/ директории НЕ удаляются при helm uninstall — специально, чтобы не сломать другие релизы, использующие тот же CRD.
  • Helm hooks (Jobs для migrations) не tracked как часть release. Они создаются, выполняются — и helm rollback не вернёт их назад.

Killer-моменты

  • Helm 3 client-only. Нет Tiller, нет server-side компонентов. RBAC проверяется на пользователя, а не на демона с cluster-admin.
  • Release stored as Secret в namespace. Удалил Secret вручную — Helm “забыл” про release, но resources остались.
  • CRDs не удаляются при helm uninstall. По дизайну, чтобы не сломать другие релизы с теми же CRDs.
  • Один Chart → много Release-ов. helm install web bitnami/redis и helm install cache bitnami/redis — два независимых инстанса с разной историей.
  • Templates не валидный YAML. Линтеры YAML на template-файлы ругаются. helm template для рендера локально, helm lint для проверки.
  • appVersion vs version в Chart.yaml. version — версия Chart-а (увеличивается при изменении templates). appVersion — версия упакованного приложения (Redis 7.2 → 7.4 без изменения chart структуры).

Проверка знанийKnowledge check
Чем Helm 3 принципиально отличается от Helm 2 в архитектуре, и почему это важно для безопасности?
ОтветAnswer
Helm 2 имел серверную часть Tiller — Deployment с cluster-admin правами. Helm CLI отправлял templates Tiller-у, тот рендерил и применял. Проблема: любой пользователь с доступом к Tiller получал cluster-admin (RBAC bypass — Tiller проверял свои права, не пользователя). Helm 3 убрал Tiller — всё клиент-сайд, использует kubeconfig пользователя, RBAC применяется напрямую. Релизы хранятся как Secrets в namespace релиза. Это устранило весь класс security-проблем эскалации привилегий.
Проверка знанийKnowledge check
helm install web bitnami/redis создал релиз. helm install cache bitnami/redis в том же namespace. Что произойдёт?
ОтветAnswer
Создадутся ДВА независимых Redis-инстанса — оба из одного Chart, но с разными именами релизов (web и cache). У каждого свой набор Pod-ов, своя revision history, свой Release Secret (sh.helm.release.v1.web.v1 и sh.helm.release.v1.cache.v1). Имена resources внутри обычно префиксуются именем релиза (через .Release.Name в template), так что web-redis-master и cache-redis-master не конфликтуют. Helm specifically спроектирован для multi-instance — один chart можно installят многократно.
Проверка знанийKnowledge check
Ты сделал helm install web ./mychart. Потом удалил Release Secret вручную через kubectl delete secret. Что с релизом?
ОтветAnswer
Helm 'забыл' про релиз. helm list его не показывает. Но все K8s resources (Deployment, Service, ConfigMap), которые helm создал — остались в кластере и работают. helm uninstall web не сработает (Helm не знает, что чистить). helm upgrade web ./mychart выдаст 'release: not found'. Восстановление: либо kubectl delete руками по labels (app.kubernetes.io/managed-by=Helm,app.kubernetes.io/instance=web), либо helm install web ./mychart --replace (создаст release заново, попытается adopt существующие resources).
Проверка знанийKnowledge check
Почему CRDs из директории crds/ в Chart не удаляются при helm uninstall, и какая это создаёт проблему?
ОтветAnswer
По дизайну: CRDs часто используются несколькими релизами / тулами. Если один helm uninstall удалит CRD — все CustomResources, использующие этот CRD (даже из других релизов), исчезнут вместе с ним (garbage collection через ownerReferences). Helm играет осторожно — CRDs устанавливаются один раз и остаются. Проблема: upgrade CRD при helm upgrade тоже не происходит автоматически (только install). Для обновления CRD надо kubectl apply -f crds/ вручную или использовать helm.sh/hook: crd-install (deprecated в Helm 3 — теперь рекомендуется отдельный chart для CRDs).

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5