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_valNOTE: Синтаксис `{{-`
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.comProfit!
Все примеры кода, приведенные в этой статье, можно найти в репозитории. Если вам понравилась эта статья, пожалуйста, поставьте звезду ⭐ репозиторию и подпишитесь на меня на GitHub, чтобы получать уведомления о новых уроках и контенте.
Полезные ссылки
Больше информации на:
- https://helm.sh/docs/chart_template_guide/named_templates/
- https://helm.sh/docs/chart_template_guide/getting_started/