github.com/tiancandevloper/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.