20 липня 2026 р.
Helm Charts для початківців: створення та розгортання

Helm спрощує керування Kubernetes-маніфестами, коли одного Deployment і Service вже недостатньо. Замість копіювання майже однакових YAML-файлів для test, staging та production команда описує ресурси як шаблони, а відмінності переносить у values. У результаті один пакет можна встановлювати повторно, оновлювати контрольованою командою та повертати до попередньої ревізії.
Цей матеріал побудований навколо невеликого web-сервісу. Ми створимо chart, приберемо зайві генераторні файли, опишемо параметри контейнера, підготуємо Deployment і Service, перевіримо результат локально та виконаємо безпечне встановлення. Перед початком потрібні робочий кластер Kubernetes, налаштований kubectl і Helm у локальному середовищі або на службовому runner. Якщо сам кластер ще не готовий, спочатку варто пройти практичне встановлення Kubernetes на Ubuntu 24.04.
Helm не замінює знання Kubernetes. Chart зрештою генерує звичайні маніфести, які API-сервер перевіряє та зберігає. Тому важливо розуміти, які ресурси утворяться після рендерингу, а не сприймати успішну команду Helm як гарантію правильної архітектури.
Як влаштований Helm Chart і що саме ми створюємо
Chart — це каталог із метаданими, типовими значеннями та Go-шаблонами Kubernetes-ресурсів. Після встановлення chart утворюється release: конкретний екземпляр пакета з власним ім’ям, namespace, values та історією ревізій. Один chart можна встановити кілька разів, наприклад як `web-stage` і `web-prod`, не дублюючи шаблони.
Перевіримо доступність інструментів і з’єднання з кластером:
helm version
kubectl cluster-info
kubectl get nodesСтворимо початкову структуру:
mkdir -p deploy/helm
cd deploy/helm
helm create web-app
find web-app -maxdepth 2 -type f | sortКоманда `helm create` генерує повний стартовий приклад. У каталозі з’являться `Chart.yaml`, `values.yaml`, `.helmignore`, директорія `templates` і тестовий шаблон. Для навчального chart краще одразу видалити те, що ми не будемо використовувати, і залишити тільки зрозумілі ресурси:
rm -rf web-app/templates/tests
rm -f web-app/templates/ingress.yaml
rm -f web-app/templates/hpa.yaml
rm -f web-app/templates/serviceaccount.yaml`Chart.yaml` описує сам пакет. Поле `version` — версія chart, а `appVersion` — версія застосунку; це різні поняття. Мінімальний файл має такий вигляд:
apiVersion: v2
name: web-app
description: Helm chart for a small web service
type: application
version: 0.1.0
appVersion: "1.0.0"Під час зміни шаблонів або values версію chart варто підвищувати за правилами SemVer. `appVersion` оновлюють разом із версією контейнера, але Helm не використовує це поле для автоматичного вибору image tag. Зв’язок між ними потрібно описати явно у values або процесі релізу.
Як винести налаштування у values.yaml
`values.yaml` містить безпечні типові значення. Те, що змінюється між середовищами, не слід жорстко записувати у Deployment. Почнемо з образу, кількості реплік, порту та ресурсів:
replicaCount: 2
image:
repository: ghcr.io/example/web-app
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 3000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512MiУ production не варто використовувати плаваючий tag `latest`: з ним складніше відтворити конкретну ревізію та зрозуміти, який образ працює в pod. Краще передавати номер версії або digest із CI/CD. Паролі, токени та приватні ключі також не повинні лежати у відкритому `values.yaml`. Для них використовують Kubernetes Secret, зовнішній secret-manager або інтеграцію на рівні платформи.
Для staging створимо окремий файл, який містить лише відмінності:
# values-staging.yaml
replicaCount: 1
image:
tag: "1.1.0-rc.2"
resources:
requests:
cpu: 50m
memory: 64MiПід час виконання Helm об’єднає типові values із файлом середовища. Так одна схема ресурсів залишається спільною, а команда бачить конкретні відмінності у короткому reviewable-файлі. Якщо релізи вже автоматизуються, values-файли та версію образу зручно включити у побудову й оптимізацію CI/CD, щоб ручний параметр не відрізнявся від стану репозиторію.
Як написати Deployment і Service як шаблони
Файли з каталогу `templates` проходять через Go template engine. Значення з `values.yaml` доступні через об’єкт `.Values`, метадані chart — через `.Chart`, а дані конкретного release — через `.Release`.
Створимо `templates/deployment.yaml`:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
resources:
{{ toYaml .Values.resources | indent 12 }}Потім додамо `templates/service.yaml`:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
type: {{ .Values.service.type }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}Селектори Deployment, pod labels і селектори Service повинні збігатися. Це одна з найпоширеніших причин ситуації, коли pod працює, але Service не має endpoints. Значення, що вставляються як рядки, доцільно брати в лапки або пропускати через `quote`. Для багаторядкових фрагментів важливі `toYaml`, `indent` і `nindent`: неправильний відступ породжує синтаксично пошкоджений YAML.
У більших chart повторювані labels і назви виносять у `templates/_helpers.tpl` та підключають через `include`. Для першого прикладу явні поля корисніші: легше побачити, які дані Helm підставляє і який маніфест отримує Kubernetes.
Як перевірити chart до встановлення
Спочатку перевіряємо структуру й базові практики:
helm lint ./web-app
helm lint ./web-app -f values-staging.yamlДалі рендеримо готові маніфести локально. Цей крок не змінює кластер і дозволяє перевірити імена, image tag, labels, ресурси та відступи:
helm template web-stage ./web-app \
--namespace web-stage \
-f values-staging.yaml \
--debug > /tmp/web-stage-rendered.yaml
kubectl apply --dry-run=client \
-f /tmp/web-stage-rendered.yaml`helm template` не може повністю підтвердити сумісність із конкретним кластером: локальний рендеринг не перевіряє всі server-side обмеження та встановлені CRD. Якщо є доступ до тестового кластера, корисний server-side dry run:
helm upgrade --install web-stage ./web-app \
--namespace web-stage \
--create-namespace \
-f values-staging.yaml \
--dry-run=server \
--debugВивід dry run може містити згенеровані Secret, тому його не можна бездумно зберігати у публічних CI-логах. Перед реальним встановленням перевірте, що команда спрямована у правильний kube-context:
kubectl config current-context
kubectl config get-contextsТакий preflight особливо важливий, коли одна робоча станція має доступ до кількох кластерів. Технічний супровід шаблонів, кластерів і релізного контуру зазвичай є частиною системних DevOps-послуг, а не одноразовою генерацією YAML.
Встановлення, оновлення та типові помилки
Для першого й наступних запусків зручно використовувати одну idempotent-команду `upgrade --install`:
helm upgrade --install web-stage ./web-app \
--namespace web-stage \
--create-namespace \
-f values-staging.yaml \
--atomic \
--wait \
--timeout 5m`--wait` очікує готовності потрібних ресурсів, а `--atomic` у разі невдалого оновлення намагається повернути release до попереднього стану. Після встановлення перевіряємо не лише статус Helm, а й реальні Kubernetes-об’єкти:
helm status web-stage -n web-stage
helm history web-stage -n web-stage
kubectl get deploy,pods,svc -n web-stage
kubectl describe deployment web-stage -n web-stageЯкщо потрібно явно повернутися до попередньої ревізії, спочатку дивимося історію, а потім виконуємо rollback на обраний номер:
helm history web-stage -n web-stage
helm rollback web-stage 1 -n web-stage --waitТипова помилка початківця — редагувати створені Helm ресурси вручну через `kubectl edit`. Наступний upgrade перезапише таку зміну, а фактична конфігурація розійдеться з репозиторієм. Виправлення потрібно вносити у chart або values і застосовувати новою ревізією.
Друга проблема — змішування конфігурації та секретів. Зручність `--set password=...` оманлива: параметр може потрапити до shell history, журналів runner або metadata release. Секретні значення слід передавати контрольованим способом і обмежувати доступ до журналів.
Третя помилка — надмірна кількість умов у шаблонах. Коли один chart десятками `if` і `range` намагається підтримувати несумісні архітектури, його важко тестувати. Краще мати невеликий передбачуваний API values та розділити справді різні сценарії.
Четверта проблема — оновлення без `helm lint`, рендерингу й перевірки kube-context. Синтаксично правильний template ще може створити неправильний Service selector, небезпечний image tag або ресурси не в тому namespace. Перевірки мають бути частиною кожного pull request, а не разовою дією автора chart.
Висновок
Перший корисний Helm Chart не повинен бути універсальним. Достатньо описати один застосунок, винести змінні параметри у `values.yaml`, створити зрозумілі шаблони Deployment і Service та навчитися аналізувати результат до встановлення. Головна перевага Helm з’являється не від скорочення кількості YAML, а від повторюваного release-процесу з версіями, values та історією змін.
Робочий мінімум виглядає так: `helm create` для каркаса, очищення зайвих шаблонів, явні values, `helm lint`, локальний `helm template`, server-side dry run у тестовому кластері й тільки після цього `helm upgrade --install`. Додайте до цього фіксовані image tags, перевірку namespace, readiness probe та контрольовані секрети — і chart стане придатною основою для staging, а не лише навчальним прикладом.
Наступний крок після першого chart — винести повторювані labels у helpers, додати `values.schema.json`, автоматичне тестування рендерингу та пакування версій. Але ці покращення мають з’являтися поступово, коли команда вже розуміє згенеровані Kubernetes-ресурси й може пояснити призначення кожного параметра.