м. Київ, вул. Кирилівська 102

20 липня 2026 р.

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

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`, не дублюючи шаблони.

Перевіримо доступність інструментів і з’єднання з кластером:

bash
helm version
kubectl cluster-info
kubectl get nodes

Створимо початкову структуру:

bash
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 краще одразу видалити те, що ми не будемо використовувати, і залишити тільки зрозумілі ресурси:

bash
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` — версія застосунку; це різні поняття. Мінімальний файл має такий вигляд:

yaml
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. Почнемо з образу, кількості реплік, порту та ресурсів:

yaml
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 створимо окремий файл, який містить лише відмінності:

yaml
# 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`:

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`:

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 до встановлення

Спочатку перевіряємо структуру й базові практики:

bash
helm lint ./web-app
helm lint ./web-app -f values-staging.yaml

Далі рендеримо готові маніфести локально. Цей крок не змінює кластер і дозволяє перевірити імена, image tag, labels, ресурси та відступи:

bash
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:

bash
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:

bash
kubectl config current-context
kubectl config get-contexts

Такий preflight особливо важливий, коли одна робоча станція має доступ до кількох кластерів. Технічний супровід шаблонів, кластерів і релізного контуру зазвичай є частиною системних DevOps-послуг, а не одноразовою генерацією YAML.

Встановлення, оновлення та типові помилки

Для першого й наступних запусків зручно використовувати одну idempotent-команду `upgrade --install`:

bash
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-об’єкти:

bash
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 на обраний номер:

bash
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-ресурси й може пояснити призначення кожного параметра.

📞