Unsplash by Frank Eiffert

Helm — мощный инструмент для применения, обновления и управления приложениями в Kubernetes. Сообщество Helm создает множество чартов с открытым исходным кодом. Вы можете развернуть Redis, Nginx или Prometheus Operator с помощью одной команды. И они поставляются со всем, что нужно, например с Ingress.

Команда Mail.ru Cloud Solutions перевела статью, автор которой описывает быстрый способ создания базового чарта, показывает полезные команды и делится лучшими практиками. Он не останавливается на аспектах языка шаблонов Go, поскольку большинство из них описаны в документации по Helm. В этом руководстве — более абстрактные аспекты и идеи по улучшению рабочего процесса.

Создание базовой структуры чарта


Начните с простой команды, которая создаст пример структуры чарта:

$ helm create basic
Creating basic
$ tree basic
basic/
+-- charts
+-- Chart.yaml
+-- templates
¦   +-- deployment.yaml
¦   +-- _helpers.tpl
¦   +-- ingress.yaml
¦   +-- NOTES.txt
¦   +-- serviceaccount.yaml
¦   +-- service.yaml
¦   L-- tests
¦       L-- test-connection.yaml
L-- values.yaml

Вот и всё, что нужно для создания готового к развертыванию чарта. Такой чарт позволяет развернуть приложение со всеми необходимыми компонентами. Если вы заглянете в values.yaml, то увидите, что это приложение развернет Nginx.

Развернуть чарт так же просто, как и создать:

$ helm install basic

Команда template — ваш лучший друг


Непосредственно перед установкой и после изменений в чарте следует проверять, всё ли обрабатывается в шаблонах должным образом.

Чтобы проверить, что именно будет развернуто в кластере, используйте команду:

$ helm template basic

Команда выведет каждый YAML, созданный всеми шаблонами. Если хотите увидеть результат только одного шаблона, используйте:

$ helm template basic -x templates/service.yaml

Результат будет примерно таким:

---
# Source: basic/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-basic
  labels:
    app.kubernetes.io/name: basic
    helm.sh/chart: basic-0.1.0
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: "1.0"
    app.kubernetes.io/managed-by: Tiller
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: basic
    app.kubernetes.io/instance: release-name

Для тестирования шаблона с настраиваемыми значениями используйте:

$ helm template basic -x templates/service.yaml -f \ mypath/tocustomvalues.yaml

Сгенерированный шаблон можно протестировать на кластере при помощи команды:

$ helm install basic --dry-run --debug

LINT!


Перед отправкой в репозиторий вы можете добавить еще один шаг для четкой проверки кода — linting (статистический анализ):

$ helm lint basic/
==> Linting basic/
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, no failures

Helm работает с функциями


Если заглянуть в каталог шаблонов чарта, то можно увидеть _helpers.tpl. Сюда вы можете добавить свои функции, они будут доступны по всему чарту. Пример функции может выглядеть так:

{{/*
Expand the name of the chart.
*/}}
{{- define "basic.name" -}} 
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 
{{- end -}}

Использование функции в шаблоне указывают при помощи функции include:

app.kubernetes.io/name: {{ include "basic.name" . }}

Мета-метки


Важная часть Kubernetes — правильное использование меток. Это очень важно, если вы используете Helm для развертывания множества манифестов. Чтобы легко добавлять метки для поиска ресурсов, управляемых Helm, можно использовать собственные функции:

{{/*
Common labels
*/}}
{{- define "basic.labels" -}} 
app.kubernetes.io/name: {{ include "basic.name" . }}
helm.sh/chart: {{ include "basic.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}

И теперь несложно добавить несколько меток в чарт:

apiVersion: v1
kind: Service
metadata:
  name: {{ include "basic.fullname" . }}
  labels:
{{ include "basic.labels" . | indent 4 }}
...

Если хотите отыскать сервисы, созданные с помощью этого чарта, то используйте команду:

$ kubectl get svc -l helm.sh/chart=basic-0.1.0

Комментарии вас спасут


Возможны два типа комментариев:

  • # — простой комментарий, который остается в результирующем YML после обработки.
  • {{- /* … */ -}} — комментарий, который отбрасывается обработчиком шаблонов.


# app files volume
        {{- /*
          App files are configmaps created by cloud-app-play-files chart.
          App files contains files specific for app and environment.
          App name should be same as in deployment of cloud-app-play-files chart.
        */ -}} 
        {{- if .Values.include.appDir }}
        - name: {{ $appName }}-files
          configMap:
            name: {{ $appName }}-files

Вывод шаблона будет таким:

       # app files volume
       - name: app-notification-files
         configMap:
           name: app-notification-files

Как вы видите, сгенерированный манифест содержит только комментарий простого типа. Какой тип использовать — решать вам. Но комментарии к шаблонам полезны, если вы описываете в YAML функции более сложных конвейеров или зависимостей.

Еще важно помнить, что комментарии, начинающиеся с #, тоже парсятся. Если вы поместите шаблон Go в комментарий, то он будет вычислен. Так что комментарии тоже могут быть шаблонами.

Обязательно ведите документацию


Документация для чартов незаменима, особенно если вы хотите опубликовать чарт. Самый простой способ создавать и поддерживать документы — использовать пакет Golang с именем helm-docs. С его помощью вы можете сгенерировать README.md, содержащий таблицы значений, версий и описания из values.yaml и chart.yaml или использовать другие пользовательские файлы.


Пример взят с https://github.com/norwoodj/helm-docs

Как видите, добавление в комментарии имени с — приводит к одной строке в таблице. Кроме того, в таблице содержится дополнительная информация, например, описание чарта, имя и версия. Helm-docs можно интегрировать в прекоммит вместе с линтингом. Сделать это просто:

$ helm-docs
INFO[2020-07-23T15:30:38+02:00] Found Chart directories [.]                 
INFO[2020-07-23T15:30:38+02:00] Generating README Documentation for chart .

Магия субчартов


Когда ваш чарт становится монстром, создающим всю архитектуру, лучше всего разделить некоторые компоненты чарта на более мелкие. Их называют субчартами или дочерними чартами.

Субчарты развертываются одновременно с основным чартом. Значения для субчартов можно предоставить в том же файле values.yaml, что и для основного чарта. Еще их можно подключать из GitHub, но для статьи я создам субчарт локально.

Чтобы начать работу с новым субчартом, от которого зависит основной чарт, создайте каталог charts внутри папки основного чарта. Затем создайте базовый чарт:

$ mkdir charts
$ cd charts
$ helm create subbasic

Чтобы подключить субчарт, измените определение основного чарта:

apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: basic
version: 0.1.0
dependencies:
  - name: subbasic       

Теперь каждый раз при запуске команды helm install разворачивается не только основной чарт, но и субчарт. Чтобы переопределить референсное имя субчарта при развертывании в сервисе, добавьте в values.yaml основного чарта следующие команды:

subbasic:
 service:
   type: NodePort
 nameOverride: "jojo"

Теперь запустите команду template и посмотрите измененный вывод сервиса субчарта. Тип сервиса изменится вместе с названием:

---
# Source: basic/charts/subbasic/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: release-name-jojo
  labels:
    app.kubernetes.io/name: jojo
    helm.sh/chart: subbasic-0.1.0
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/version: "1.0"
    app.kubernetes.io/managed-by: Tiller
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: jojo
    app.kubernetes.io/instance: release-name

Важное примечание: субчарты не могут принимать значения из родительских чартов.

Моменты, о которых часто забывают


Еще несколько моментов:

  1. Имена ресурсов — максимум 63 символа.
  2. Имена ресурсов могут состоять только из цифр, строчных букв, «-» или «.».
  3. Размер чарта — не более 1 МБ. Это особенно важно, если вы используете прикрепление файлов.
  4. В чарте есть функция для парсинга .tpl.
  5. Вы можете указать ресурсы, которые останутся после удаления деплоя чарта командой helm delete.

Ну вот и всё!


Теперь вы можете написать свой первый чарт. Стоит упомянуть о прикреплении файлов — чарты не подходят для добавления файлов и сохранения их структуры в каталогах. Но на странице с рекомендациями вы не найдете информации о том, что следует держать в чарте, а что — нет.

Helm — довольно молодой инструмент, но с большим потенциалом. Не забывайте, что линтинг, генерация документации и даже dry-run шаблоны в кластере могут быть частью CI. Для GitHub уже доступны Helm Workflow.

Удачи!

Что еще почитать:

  1. Устройство Helm и его подводные камни.
  2. Автогенерация секретов в Helm.
  3. Наш канал Вокруг Kubernetes в Телеграме.