6 мин чтения
Helm-шпаргалка: как работать с контекстом в именованных шаблонах
Небольшая заметка про работу и управление контекстом в функциях include и template внутри именованных шаблонов Helm.
Обзор
Рассмотрим на простом примере определение именованных шаблонов через define
, работу с контекстом в таких шаблонах, определение переменных и передачу их в кастомный контекст.
Начало
Для начала создадим чарт для экспериментов с помощью запуска команды
helm create helm-context-demo
Для тестовых целей создадим отдельный yaml файл по пути templates/test/test-helm.yaml
. Теперь интересующие нас файлы проекта представленны следующей иерархией
mychart/
Chart.yaml
values.yaml
charts/
templates/
_helpers.tpl
test/
test-helm.yaml
...
Вспомним быстро для чего предназначены каждый файл и папка:
Сhart.yaml
- определение и метаданные чартаvalues.yaml
- файл содержит значения по умолчанию для чартаtemplates/
- каталог предназначен для файлов шаблонов: все файлы из этого каталога рендерятся в выходной файл._helpers.tpl
- файл может содержать именнованные шаблоны, которые могут повторно использоваться вtemplates
Вызывать рендеринг будем следующими командами
helm template . # собрать все шаблоны из /templates
helm template -s templates/tests/test-helm.yaml . # собрать один файл
Создаем именованный шаблон
Создадим простой именнованный шаблон с спомощью define
, а затем используем его в test-helm.yaml.
{{ define "my.first.template" }}
simple_key: simple_value
chart_name: {{ .Chart.name }}
{{end}}
Использовать можно так {{ include "my.first.template" . }}
. В этом случае передаем текущий контекст.
Также можно переопределить контекст, передав, например, пустую строку {{ include "my.first.template" "" }}
.
В данном случае вызов рендеринга приведет к ошибке.
Можно в контекст передать любую переменную или любой объект и затем с ним работать, например:
{{ include "my.first.template" (dict "a" "a_val") }}
Или через переменную
{{ $custom_context := (dict "a" "a_val") }}
{{ include "my.first.template" $custom_context }}
Результата вызова шаблона также можно сохранить как строку в переменную, а затем вывести ее значение:
{{ $custom_context := (dict "a" "a_val") }}
{{ $result := (include "my.first.template" $custom_context) }}
{{ $result }}
Можно видоизменить шаблон, чтобы он отрабатывал без ошибок при каждом использовании добавив проверки на пустое значение в контексте
{{- define "my.first.template" -}}
simple_key: simple_value
{{- if and (not (empty .)) (not (empty .Chart)) }}
chart_name: {{ .Chart.Name }}
{{- end }}
{{- if and (not (empty .)) (not (empty .a)) }}
a: {{ .a }}
{{- end }}
{{- end -}}
Теперь при вызове примера с $custom_context будет сгенерирован следующий шаблон
---
# Source: helm-context/templates/tests/test-helm.yaml
simple_key: simple_value
a: a_val
NOTE: Синтаксис `{{-`
Cинтаксис фигурных скобок в объявлениях шаблонов можно изменить с помощью специальных символов, чтобы заставить механизм шаблонов удалять пробельные символы. {{-
(с добавлением тире и пробела) указывает, что пробельные символы нужно удалить слева, а -}}
означает, что справа.
Так например, если бы мы не использовали дефис в предыдущем примере возле if
, то мы бы получили вот такой вывод
---
# Source: helm-context/templates/tests/test-helm.yaml
simple_key: simple_value
a: a_val
Контекст, что он содержит, как переопределять
Контекст в шаблонах Helm представляет собой совокупность доступных переменных и объектов, которые можно использовать в шаблонах для генерации конфигурации Kubernetes. Он включает в себя глобальный контекст, который доступен во всех шаблонах чарта, а также локальные контексты, которые могут быть определены в пределах конкретных шаблонов.
Глобальный контекст в helm доступен по умолчанию в каждом шаблоне. В этом контексте доступны по умолчанию следующие объекты:
.Values
, .Release
, .Chart
, .Capabilities
, .Files
, .Template
.
Через точку можно получить доступ к объектам текущего контекста. Передав .
в шаблон мы передаем текущий контекст в шаблон на уровень ниже. Если контекст не изменяется в шаблоне, то при таком подходе через точку дочернему шаблону будет доступен верхний контекст.
Контекст можно переопределить передав свою собственную переменную. В таком случае доступ ко всем дефолтным объектам глобального шаблона будет утерян. Исключением является контекст внутри функций with
и range
: в таком шаблоне глобальный контекст может быть виден через $
.
Как я показывал ранее переопределить контекст в шаблоне можно вот так: {{ include "my.first.template" (dict "a" "a_val") }}
. После этого вызова объект .Chart
будет не доступен шаблону.
Переменные в контекст
Вот пример определения переменной внутри шаблона.
{{- define "my.second.template" -}}
{{ $var := "my string var" }}
x: {{ $var | quote }}
{{- end -}}
---
# Source: helm-context/templates/tests/test-helm2.yaml
x: "my string var"
Переменные существуют только в контексте шаблона - внутри define. Нельзя использовать переменную, объявленную снаружи блока определения шаблона, однако можно передать переменную в контекст.
{{- define "my.second.template" -}}
{{ $var := "my string var" }}
x: {{ $var | quote }}
nested: {{ include "my.second.template.nested" (dict "var" $var) | nindent 2 }}
{{- end -}}
{{- define "my.second.template.nested" -}}
x: {{ .var | quote }}
isNested: true
{{- end -}}
Будет выведено
# Source: helm-context/templates/tests/test-helm2.yaml
x: "my string var"
nested:
x: "my string var"
isNested: true
Однако теперь в nested шаблоне не доступно никаких объектов: ни .Values
, ни .Chart
, ни других. Чтобы получить к ним доступ можно пробросить явно необходимые объекты в контекст, например:
{{- define "my.second.template" -}}
{{ $var := "my string var" }}
x: {{ $var | quote }}
nested: {{ include "my.second.template.nested" (dict "var" $var "Chart" .Chart) | nindent 2 }}
{{- end -}}
{{- define "my.second.template.nested" -}}
x: {{ .var | quote }}
isNested: true
chartName: {{ .Chart.Name }}
{{- end -}}
# Source: helm-context/templates/tests/test-helm2.yaml
x: "my string var"
nested:
x: "my string var"
isNested: true
chartName: helm-context
Изменять существующий контекст нельзя - он является иммутабельным.
Рассмотрим пример с использованием .Values
, для этого добавим такой список в values.yaml
hosts:
- "www.example0.com"
- "www.example1.com"
- "www.example2.com"
Определим шаблон, который создает конфигурации серверов с использованием случайного идентификатора и списка хостов, указанных в переменной .Values.hosts. Каждая конфигурация сервера включает уникальный идентификатор, состоящий из сгенерированного идентификатора в родительском шаблоне и индекса хоста, а также сам хост.
{{- define "my.third.template" -}}
{{ $id := (randAlphaNum 5) }}
id: {{ $id | quote }}
servers: {{ include "my.third.template.servers" (dict "id" $id "Values" .Values) }}
{{- end -}}
{{- define "my.third.template.servers" -}}
{{- $hosts := .Values.hosts -}}
{{- range $i, $host := $hosts }}
- id: {{ $.id }}-{{ $i }}
host: {{ $host }}
{{- end }}
{{- end -}}
Вывод:
# Source: helm-context/templates/tests/test-helm3.yaml
id: "pgm7b"
servers:
- id: pgm7b-0
host: www.example0.com
- id: pgm7b-1
host: www.example1.com
- id: pgm7b-2
host: www.example2.com
Profit!
Все примеры кода, приведенные в этой статье, можно найти в репозитории. Если вам понравилась эта статья, пожалуйста, поставьте звезду ⭐ репозиторию и подпишитесь на меня на GitHub, чтобы получать уведомления о новых уроках и контенте.
Полезные ссылки
Больше информации на:
- https://helm.sh/docs/chart_template_guide/named_templates/
- https://helm.sh/docs/chart_template_guide/getting_started/