Анатомия Helm-чарта

Уровень: intermediate ~55 мин Практика: Vikunja (AGPL-3.0)

Что нужно знать перед уроком

  • M3.07 — Cleanup registry — у вас должны быть собранные и опубликованные образы Vikunja, которые сейчас нужно задеплоить

Что нужно знать перед уроком

M3 целиком — у вас есть собранные образы Vikunja в registry. Теперь нужно превратить набор Kubernetes-манифестов (Deployment/Service/… из M1) в шаблонизируемый, версионируемый пакет — Helm-чарт.

Теория

Структура директории чарта

vikunja/
├── Chart.yaml          # метаданные: имя, версия, appVersion, зависимости
├── values.yaml          # значения по умолчанию для шаблонов
├── values.schema.json    # (опционально) JSON Schema для валидации values
├── charts/              # вложенные чарты-зависимости (sub-charts)
├── crds/                # CustomResourceDefinition, устанавливаемые ДО шаблонов
├── templates/            # шаблоны манифестов Kubernetes
│   ├── deployment.yaml
│   ├── service.yaml
│   └── _helpers.tpl      # общие шаблонные функции (начинаются с _, не рендерятся как отдельный манифест)
├── LICENSE               # (опционально)
├── README.md             # (опционально)
└── .helmignore            # маски файлов, исключаемых из упаковки чарта

Chart.yaml — метаданные пакета: name, version (версия самого чарта, semver), appVersion (версия приложения внутри — может отличаться от версии чарта), dependencies (список sub-charts с версиями и репозиториями). values.yaml — значения, доступные шаблонам через объект .Values. charts/ — механизм композиции: чарт может зависеть от других чартов (например, чарт Vikunja мог бы зависеть от чарта PostgreSQL, если бы БД разворачивалась тем же релизом, а не через managed-модуль платформы — но для Application-пакетов курса зависимость от БД идёт через Module, M6 урок 1, а не через sub-chart).

Критично: values.yaml НЕ шаблонизируется

Это первое, что путает новичков: values.yaml — это обычный статический YAML-файл. Синтаксис {{ }} внутри него не обрабатывается движком шаблонов — если написать image: {{ .Chart.AppVersion }} прямо в values.yaml, это останется буквальной строкой "{{ .Chart.AppVersion }}", а не подставленным значением. Шаблонизация (Go templates + Sprig-функции) применяется только к файлам внутри templates/crds/ в некоторых конфигурациях) — именно там {{ .Values.image.tag }} реально разворачивается в конкретное значение, взятое из values.yaml или переопределённое при установке.

1
2
3
4
5
# values.yaml — статический YAML, БЕЗ шаблонизации
image:
  repository: registry.example.com/vikunja/backend
  tag: "v0.24.0"
replicaCount: 2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# templates/deployment.yaml — ЗДЕСЬ работает шаблонизация
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-backend
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
        - name: backend
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

Встроенные объекты контекста шаблонов

ОбъектЧто содержит
.Release.Release.Name (имя релиза/инстанса), .Release.Namespace, .Release.IsInstall/.Release.IsUpgrade (текущая операция), .Release.Revision (номер ревизии)
.Chartсодержимое Chart.yaml.Chart.Name, .Chart.Version, .Chart.AppVersion
.Valuesитоговые значения после слияния values.yaml + переопределений при установке (--set/-f custom-values.yaml)
.Capabilitiesинформация о целевом кластере — .Capabilities.KubeVersion, .Capabilities.APIVersions.Has "batch/v1" (проверка доступности API)
.Filesдоступ к произвольным нешаблонным файлам чарта через .Files.Get "config.json"

{{ .Chart.Name }}-{{ .Chart.Version }} — типичный пример использования .Chart для генерации детерминированных имён. .Capabilities.APIVersions.Has особенно полезен для шаблонов, которые должны работать на разных версиях Kubernetes с разными доступными API-группами (например, условный выбор между policy/v1 и устаревшим policy/v1beta1).

crds/ — устанавливаются отдельно и раньше всех шаблонов

CRD в директории crds/ (в отличие от templates/) устанавливаются Helm до рендера и применения остальных шаблонов, и не шаблонизируются вообще (файлы в crds/ — чистый статический YAML, без доступа к .Values). Это архитектурное решение: CRD должны существовать в кластере раньше любых Custom Resource, которые их используют, — если бы CRD рендерились как обычный шаблон вперемешку с остальными манифестами, порядок установки не был бы гарантирован. Важно помнить: Application-пакеты курса не могут объявлять CRD вообще (M2 урок 1, M5 урок 5) — эта директория актуальна для Module, а для Application-разработчика — знание общего Helm-контекста.

Частые ошибки и подводные камни

  • Пытаться использовать {{ }} внутри values.yaml и удивляться, что не работает. values.yaml — статический файл, шаблонизация только в templates/.
  • Путать version (версию чарта) с appVersion (версией приложения внутри). Чарт может обновляться (менять version) без изменения версии самого приложения appVersion, и наоборот — обновление приложения не всегда требует изменения структуры чарта.
  • Забыть про .helmignore. Без него в упаковку чарта могут попасть ненужные файлы (например, .git/, локальные тестовые values) — раздувая размер артефакта и потенциально утекая секреты.

Практика в кластере

Практики в кластере пока нет — сначала нужно создать сам чарт локально.

Практика разработки

🧩 Практика урока: Vikunja · лицензия AGPL-3.0
  1. Создайте базовую структуру чарта для Vikunja:
1
2
mkdir -p vikunja-chart/templates
cd vikunja-chart
1
2
3
4
5
6
7
# Chart.yaml
apiVersion: v2
name: vikunja
description: Self-hosted менеджер задач
type: application
version: "0.1.0"
appVersion: "0.24.0"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# values.yaml
backend:
  image:
    repository: registry.example.com/vikunja/backend
    tag: "v0.24.0"
  replicaCount: 1
frontend:
  image:
    repository: registry.example.com/vikunja/frontend
    tag: "v0.24.0"
  replicaCount: 1
  1. Создайте минимальный templates/deployment-backend.yaml, используя встроенные объекты:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-backend
  labels:
    app.kubernetes.io/name: {{ .Chart.Name }}
    app.kubernetes.io/instance: {{ .Release.Name }}
spec:
  replicas: {{ .Values.backend.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .Chart.Name }}
      app.kubernetes.io/instance: {{ .Release.Name }}
      component: backend
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .Chart.Name }}
        app.kubernetes.io/instance: {{ .Release.Name }}
        component: backend
    spec:
      containers:
        - name: backend
          image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
  1. Отрендерите шаблон локально (без установки в кластер) и убедитесь, что подстановка .Values/.Release/.Chart работает:
1
helm template test-instance . 2>/dev/null || nelm chart render . -r test-instance

Шпаргалка команд урока

1
2
3
helm create <name>        # генерирует шаблон чарта со всей структурой
helm template <release> <chart-dir>
helm lint <chart-dir>

Вопросы для самопроверки

Шаблонизируется ли values.yaml движком Go templates?

values.yaml читается как обычный YAML для получения значений; шаблонный синтаксис работает только внутри templates/ (и не работает в crds/).

Источник: Helm — Getting Started

Чем .Chart.Version отличается от .Chart.AppVersion?

Обновление чарта (структуры) не обязательно означает обновление приложения, и наоборот.

Источник: Helm — Chart File Structure

В каком порядке устанавливаются CRD из crds/ относительно шаблонов из templates/?

crds/ — статические файлы, устанавливаемые раньше остальных манифестов, чтобы гарантировать существование CRD до создания зависящих от них Custom Resource.

Источник: Helm — Charts

Что содержит встроенный объект .Capabilities?

.Capabilities даёт доступ к информации о кластере, на который сейчас идёт установка — полезно для условной логики, зависящей от версии/доступных API.

Источник: Helm — Built-in Objects

Может ли Application-пакет курса объявлять свои CRD в директории crds/?

Это одно из фундаментальных ограничений Application из [официальной документации Deckhouse](https://deckhouse.ru/products/kubernetes-platform/documentation/latest/architecture/marketplace/concepts.html) — CRD/cluster-wide ресурсы доступны только Module.

Источник: Deckhouse — Concepts

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Matt Butcher, Matt Farina, Josh Dolitsky. Learning Helm. 2019. ISBN 978-1492036781.

Связанные материалы