github.com/koderover/helm@v2.17.0+incompatible/docs/chart_template_guide/named_templates.md (about) 1 # Named Templates 2 3 It is time to move beyond one template, and begin to create others. In this section, we will see how to define _named templates_ in one file, and then use them elsewhere. A _named template_ (sometimes called a _partial_ or a _subtemplate_) is simply a template defined inside of a file, and given a name. We'll see two ways to create them, and a few different ways to use them. 4 5 In the "Flow Control" section we introduced three actions for declaring and managing templates: `define`, `template`, and `block`. In this section, we'll cover those three actions, and also introduce a special-purpose `include` function that works similarly to the `template` action. 6 7 An important detail to keep in mind when naming templates: **template names are global**. If you declare two templates with the same name, whichever one is loaded last will be the one used. Because templates in subcharts are compiled together with top-level templates, you should be careful to name your templates with _chart-specific names_. 8 9 One popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`. By using the specific chart name as a prefix we can avoid any conflicts that may arise due to two different charts that implement templates of the same name. 10 11 ## Partials and `_` files 12 13 So far, we've used one file, and that one file has contained a single template. But Helm's template language allows you to create named embedded templates, that can be accessed by name elsewhere. 14 15 Before we get to the nuts-and-bolts of writing those templates, there is file naming convention that deserves mention: 16 17 - Most files in `templates/` are treated as if they contain Kubernetes manifests 18 - The `NOTES.txt` is one exception 19 - But files whose name begins with an underscore (`_`) are assumed to _not_ have a manifest inside. These files are not rendered to Kubernetes object definitions, but are available everywhere within other chart templates for use. 20 21 These files are used to store partials and helpers. In fact, when we first created `mychart`, we saw a file called `_helpers.tpl`. That file is the default location for template partials. 22 23 ## Declaring and using templates with `define` and `template` 24 25 The `define` action allows us to create a named template inside of a template file. Its syntax goes like this: 26 27 ```yaml 28 {{ define "MY.NAME" }} 29 # body of template here 30 {{ end }} 31 ``` 32 33 For example, we can define a template to encapsulate a Kubernetes block of labels: 34 35 ```yaml 36 {{- define "mychart.labels" }} 37 labels: 38 generator: helm 39 date: {{ now | htmlDate }} 40 {{- end }} 41 ``` 42 43 Now we can embed this template inside of our existing ConfigMap, and then include it with the `template` action: 44 45 ```yaml 46 {{- define "mychart.labels" }} 47 labels: 48 generator: helm 49 date: {{ now | htmlDate }} 50 {{- end }} 51 apiVersion: v1 52 kind: ConfigMap 53 metadata: 54 name: {{ .Release.Name }}-configmap 55 {{- template "mychart.labels" }} 56 data: 57 myvalue: "Hello World" 58 {{- range $key, $val := .Values.favorite }} 59 {{ $key }}: {{ $val | quote }} 60 {{- end }} 61 ``` 62 63 When the template engine reads this file, it will store away the reference to `mychart.labels` until `template "mychart.labels"` is called. Then it will render that template inline. So the result will look like this: 64 65 ```yaml 66 # Source: mychart/templates/configmap.yaml 67 apiVersion: v1 68 kind: ConfigMap 69 metadata: 70 name: running-panda-configmap 71 labels: 72 generator: helm 73 date: 2016-11-02 74 data: 75 myvalue: "Hello World" 76 drink: "coffee" 77 food: "pizza" 78 ``` 79 80 Conventionally, Helm charts put these templates inside of a partials file, usually `_helpers.tpl`. Let's move this function there: 81 82 ```yaml 83 {{/* Generate basic labels */}} 84 {{- define "mychart.labels" }} 85 labels: 86 generator: helm 87 date: {{ now | htmlDate }} 88 {{- end }} 89 ``` 90 91 By convention, `define` functions should have a simple documentation block (`{{/* ... */}}`) describing what they do. 92 93 Even though this definition is in `_helpers.tpl`, it can still be accessed in `configmap.yaml`: 94 95 ```yaml 96 apiVersion: v1 97 kind: ConfigMap 98 metadata: 99 name: {{ .Release.Name }}-configmap 100 {{- template "mychart.labels" }} 101 data: 102 myvalue: "Hello World" 103 {{- range $key, $val := .Values.favorite }} 104 {{ $key }}: {{ $val | quote }} 105 {{- end }} 106 ``` 107 108 As mentioned above, **template names are global**. As a result of this, if two templates are declared with the same name the last occurrence will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with _chart specific names_. A popular naming convention is to prefix each defined template with the name of the chart: `{{ define "mychart.labels" }}`. 109 110 ## Setting the scope of a template 111 112 In the template we defined above, we did not use any objects. We just used functions. Let's modify our defined template to include the chart name and chart version: 113 114 ```yaml 115 {{/* Generate basic labels */}} 116 {{- define "mychart.labels" }} 117 labels: 118 generator: helm 119 date: {{ now | htmlDate }} 120 chart: {{ .Chart.Name }} 121 version: {{ .Chart.Version }} 122 {{- end }} 123 ``` 124 125 If we render this, the result will not be what we expect: 126 127 ```yaml 128 # Source: mychart/templates/configmap.yaml 129 apiVersion: v1 130 kind: ConfigMap 131 metadata: 132 name: moldy-jaguar-configmap 133 labels: 134 generator: helm 135 date: 2016-11-02 136 chart: 137 version: 138 ``` 139 140 What happened to the name and version? They weren't in the scope for our defined template. When a named template (created with `define`) is rendered, it will receive the scope passed in by the `template` call. In our example, we included the template like this: 141 142 ```gotpl 143 {{- template "mychart.labels" }} 144 ``` 145 146 No scope was passed in, so within the template we cannot access anything in `.`. This is easy enough to fix, though. We simply pass a scope to the template: 147 148 ```yaml 149 apiVersion: v1 150 kind: ConfigMap 151 metadata: 152 name: {{ .Release.Name }}-configmap 153 {{- template "mychart.labels" . }} 154 ``` 155 156 Note that we pass `.` at the end of the `template` call. We could just as easily pass `.Values` or `.Values.favorite` or whatever scope we want. But what we want is the top-level scope. 157 158 Now when we execute this template with `helm install --dry-run --debug ./mychart`, we get this: 159 160 ```yaml 161 # Source: mychart/templates/configmap.yaml 162 apiVersion: v1 163 kind: ConfigMap 164 metadata: 165 name: plinking-anaco-configmap 166 labels: 167 generator: helm 168 date: 2016-11-02 169 chart: mychart 170 version: 0.1.0 171 ``` 172 173 Now `{{ .Chart.Name }}` resolves to `mychart`, and `{{ .Chart.Version }}` resolves to `0.1.0`. 174 175 ## The `include` function 176 177 Say we've defined a simple template that looks like this: 178 179 ```yaml 180 {{- define "mychart.app" -}} 181 app_name: {{ .Chart.Name }} 182 app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}" 183 {{- end -}} 184 ``` 185 186 Now say I want to insert this both into the `labels:` section of my template, and also the `data:` section: 187 188 ```yaml 189 apiVersion: v1 190 kind: ConfigMap 191 metadata: 192 name: {{ .Release.Name }}-configmap 193 labels: 194 {{ template "mychart.app" .}} 195 data: 196 myvalue: "Hello World" 197 {{- range $key, $val := .Values.favorite }} 198 {{ $key }}: {{ $val | quote }} 199 {{- end }} 200 {{ template "mychart.app" . }} 201 ``` 202 203 The output will not be what we expect: 204 205 ```yaml 206 # Source: mychart/templates/configmap.yaml 207 apiVersion: v1 208 kind: ConfigMap 209 metadata: 210 name: measly-whippet-configmap 211 labels: 212 app_name: mychart 213 app_version: "0.1.0+1478129847" 214 data: 215 myvalue: "Hello World" 216 drink: "coffee" 217 food: "pizza" 218 app_name: mychart 219 app_version: "0.1.0+1478129847" 220 ``` 221 222 Note that the indentation on `app_version` is wrong in both places. Why? Because the template that is substituted in has the text aligned to the right. Because `template` is an action, and not a function, there is no way to pass the output of a `template` call to other functions; the data is simply inserted inline. 223 224 To work around this case, Helm provides an alternative to `template` that will import the contents of a template into the present pipeline where it can be passed along to other functions in the pipeline. 225 226 Here's the example above, corrected to use `nindent` to indent the `mychart_app` template correctly: 227 228 ```yaml 229 apiVersion: v1 230 kind: ConfigMap 231 metadata: 232 name: {{ .Release.Name }}-configmap 233 labels: 234 {{- include "mychart.app" . | nindent 4 }} 235 data: 236 myvalue: "Hello World" 237 {{- range $key, $val := .Values.favorite }} 238 {{ $key }}: {{ $val | quote }} 239 {{- end }} 240 {{- include "mychart.app" . | nindent 2 }} 241 ``` 242 243 Now the produced YAML is correctly indented for each section: 244 245 ```yaml 246 # Source: mychart/templates/configmap.yaml 247 apiVersion: v1 248 kind: ConfigMap 249 metadata: 250 name: edgy-mole-configmap 251 labels: 252 app_name: mychart 253 app_version: "0.1.0+1478129987" 254 data: 255 myvalue: "Hello World" 256 drink: "coffee" 257 food: "pizza" 258 app_name: mychart 259 app_version: "0.1.0+1478129987" 260 ``` 261 262 > It is considered preferable to use `include` over `template` in Helm templates simply so that the output formatting can be handled better for YAML documents. 263 264 Sometimes we want to import content, but not as templates. That is, we want to import files verbatim. We can achieve this by accessing files through the `.Files` object described in the next section.