Helm Templates: Difference between revisions
(→define) |
|||
Line 99: | Line 99: | ||
(which is something you most like don't want). | (which is something you most like don't want). | ||
For details related to whitespace handling when declaring named templates, see [[Helm_Templates#Named_Templates_and_Whitespace_Handling|Named Templates and Whitespace Handling]], below. | |||
=<span id='Scope'></span>Scopes= | =<span id='Scope'></span>Scopes= |
Revision as of 17:19, 30 August 2019
External
- The Chart Template Developer’s Guide https://helm.sh/docs/chart_template_guide/#the-chart-template-developer-s-guide
- Go Templates: https://godoc.org/text/template
- sprig Template Functions: https://godoc.org/github.com/Masterminds/sprig
Internal
Overview
Templates are files living under a chart's templates/ directory. They are written in YAML with Helm templates extensions. Upon processing by Helm, they become Kubernetes manifest files. Helm template extensions are written in the Help template language, which is based on Go templates.
The templates/ Directory
The 'templates' directory contains templates that, after combination with values, will the Kubernetes manifests. When Tiller evaluates a chart, it will send all of the files in the directory - with a few exceptions - through the template rendering engine, then collect the results and send them to to Kubernetes. Note that the NOTES.txt and _helpers.tpl files are also subject to template rendering, but they are not sent to Kubernetes as manifests.
Template names do not follow a rigid naming pattern. It is, however, recommended to use the suffix .yaml for YAML files and .tpl for helpers.
The files whose name begins with an underscore ('_') are assumed to not have a manifest inside, so they are not rendered into manifest definitions. However, they are available everywhere within other chart templates for use. These files are conventionally used to store partials and helpers. _helpers.tpl is the default location for template partials.
Template Comments
# This is a comment
{{/* Generate basic labels */}}
{{- /*
This is another comment
*/ -}}
Template Directives
A template directive, sometimes also referred as tag, is enclosed in {{ and }} blocks, and it is recommended to pad the directive with space at its left and right. The simplest directive renders a value. A value is a namespaced object, where each dot (.) separates each namespaced element. A leading dot indicates that we start with the top-most namespace for the scope.
kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap
Directives may also include functions and other constructs.
Directives and Whitespace Handling
The '{{' and '}}' directive delimiters, without any other modifications, leave the template whitespace surrounding them alone, and do not interfere with it in any way. A hyphen '-' placed after the '{{' delimiter or before the '}}' delimiter instructs the rendering engine to trim the whitespace preceding, respectively trailing the delimiter. Whitespace includes spaces, tabs, newline ('\n') and carriage return ('\r'). When encountering "-", the template engine will simply drop the corresponding whitespace until a non-whitespace character is found.
metadata:
color: {{ .Values.color }}
spec:
will produce (assuming that "color" is declared to be "blue" in values.yaml:
metadata:
color: blue
spec:
To trim preceding whitespace, use '{{-'.
metadata:
color: {{- .Values.color }}
spec:
will produce:
metadata:
color:blue
spec:
To trim trailing whitespace (whitespace includes newlines), use '-}}'.
metadata:
color: {{ .Values.color -}}
spec:
will produce:
metadata:
color: bluespec:
(which is something you most like don't want).
For details related to whitespace handling when declaring named templates, see Named Templates and Whitespace Handling, below.
Scopes
Scopes are declared with 'with'.
TODO.
Template Objects
Objects are passed into a template from the template engine. The template directives can create new objects and pass them around. There are also built-in objects, which are made available by default. Objects can be simple - have just one value -, or they can contain other objects or functions. For example the "Release" built-in object contains several other objects (like "Release.Name"). The "Files" object contains functions.
Built-in Objects
The built-in values always begin with a capital letter, based on Go's naming convention. For a fully working examples of built-in objects replacement see:
Chart
This object contains value passed into the template from the Chart.yaml file. An existing field is available as (note leading dot) .Chart.<UpperCasedFirstLetterFieldName>. It is important to capitalize the first letter of the field name, otherwise the directive evaluation fails.
Example:
{{ .Chart.Name }} {{ .Chart.Version }}
Values
This object contains values passed into template from the values.yaml file and from other user sources. An existing field is available as (note leading dot) .Values.<fieldName>. Unlike in Chart's case, the fields are allowed to keep their original capitalization. For example, a value declared as such in values.yaml:
size: 10
can be references in a template as:
kind: ConfigMap ... data: size: {{ .Values.size }}
Values can contain structured content:
characteristics: size: 10 shape: "large"
can be referenced in template as:
kind: ConfigMap ... data: size: {{ .Values.characteristics.size }} shape: {{ .Values.characteristics.shape }}
While structuring data this way is possible, the recommendation is to keep values trees shallow, favoring flatness.
Release
This object describes the release itself.
Release.Name
Exposes the release name:
{{ .Release.Name }}
Release.Revision
Exposes the release revision:
{{ .Release.Revision }}
Release.Time
Exposes the time of the release:
{{ .Release.Time }}
Release.Namespace
Exposes the namespace to be released info, if the manifest does not override:
{{ .Release.Namespace }}
Release.IsUpgrade
This is set to true if the current operation is an upgrade or rollback.
{{ .Release.IsUpgrade }}
Release.IsInstall
This is set to true if the current operation is an install.
{{ .Release.IsInstall }}
Release.Service
Exposes the releasing service - always Tiller
Files
The object provide access to all non-special files in the chart. It cannot be used to access templates. The access is provided via several functions:
Files.Get
{{ .Files.Get <file-name> }}
Files.GetBytes
Accessing Files inside Templates
TODO.
Capabilities
Provides information about the capabilities of the Kubernetes cluster:
{{ .Capabilities.APIVersions }} {{ .Capabilities.APIVersions.Has }} {{ .Capabilities.KubeVersion }} {{ .Capabilities.KubeVersion.Major| Minor|GitVersion|GitCommit|GitTreeState|BuildDate|GoVersion|Compiler|Platform}} {{ .Capabilities.TillerVersion }}
Template
Contains information about the current template that is being executed:
{{ .Template.Name }} {{ .Template.BasePath }}
Template Functions
A template function modifies data provided to the template via template objects, and it is declared inside the template, in a template directive. Template functions follow the syntax:
functionName arg1 arg2 ...
Example:
{{ quote .Values.color }}
Helm Template Function Reference
Operators
Operators are implemented as functions that return a boolean value:
{{ eq Values.color "blue" }} {{ ne }} {{ lt }} {{ gt }} {{ and }} {{ or }} {{ not }}
Template Pipelines
{{ <object> | <function1> | <function2> }}
{{ .Values.color | upper | repeat 5 }}
Template Control Structures
Flow control structures are called "actions".
if/else
if/else can be used to create conditional blocks.
TODO.
with
with specifies a scope.
TODO.
range
range provides a "for each" loop.
TODO.
Named Template Actions
A named template, sometimes called a partial, a subtemplate or an embedded template, is a template define inside of a file, and given a names. There are two different ways to create named templates, with the define action and with the template action.
Template names are global. That means if two template are declared with the same name, whichever is loaded last will be the one that will be used. Moreover, the templates in subcharts, which we are not necessarily too familiar with, are compiled together with top-level templates, so it is possible to run into template name collisions we are not aware of. For this reason, it is a good practice to name your templates with unique, chart-specific names.
One popular naming convention is to prefix the name of each defined template with the name of the chart:
{{ define "mychart.labels" }}
If everyone follows the same convention, chart-specific named templates get their own namespace and that decreases the probability of conflict that may arise due to two different charts that implement templates with the same name.
define
define declares a new named template inside of a template file, conventionally _helpers.tpl:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
By convention, define functions should have a simple documentation block {{/* ... */}} describing what they do.
The body of the partial may include directives.
Named Templates and Whitespace Handling
template
A partial defined as such can be embedded inside other template with the template action:
kind: ConfigMap
metadata:
name: ...
{{- template "mychart.labels" }}
...
When the template engine reads the file that contains the partial, it will store away the reference to "mychart.labels" until template "mychart.labels" is called. Then it will render that template inline. After rendering, the result will look like this:
kind: ConfigMap
metadata:
name: ...
labels:
generator: helm
date: 2019-08-29
...
Setting the Scope of a Template. The "template" action allows passing a scope. By default, no scope is passed by default, so objects like .Chart.Name are not found and rendered to blank space.
To pass the scope of the calling template, use "template" as such (note the dot):
...
{{- template "mychart.labels" . }}
...
In the above example, we passed the top-level (".") scope. We can pass whatever scope (template object) we want:
...
{{- template "mychart.labels" .Values }}
...
or:
...
{{- template "mychart.labels" .Values.favorite }}
...
block
block declares a special kind of fillable template area.
TODO.
The include Function
TODO.
Template Variables
TODO.
Configmap and Secrets Utility Functions
TODO.
Debugging Templates
TODO.
TODO
- https://helm.sh/docs/chart_best_practices/#templates
- https://helm.sh/docs/developing_charts/#templates-and-values
- https://helm.sh/docs/developing_charts/#know-your-template-functions
- https://helm.sh/docs/developing_charts/#quote-strings-don-t-quote-integers
- https://helm.sh/docs/developing_charts/#using-the-include-function
- https://helm.sh/docs/developing_charts/#using-the-required-function
- https://helm.sh/docs/developing_charts/#using-the-tpl-function
- https://helm.sh/docs/developing_charts/#creating-image-pull-secrets
- https://helm.sh/docs/developing_charts/#automatically-roll-deployments-when-configmaps-or-secrets-change
- https://helm.sh/docs/developing_charts/#tell-tiller-not-to-delete-a-resource
- https://helm.sh/docs/developing_charts/#using-partials-and-template-includes
- https://helm.sh/docs/chart_best_practices/#pods-and-podtemplates
- https://helm.sh/docs/chart_best_practices/#images
- https://helm.sh/docs/chart_best_practices/#imagepullpolicy
- https://helm.sh/docs/chart_best_practices/#podtemplates-should-declare-selectors