github.com/Beeketing/helm@v2.12.1+incompatible/docs/charts_tips_and_tricks.md (about)

     1  # Chart Development Tips and Tricks
     2  
     3  This guide covers some of the tips and tricks Helm chart developers have
     4  learned while building production-quality charts.
     5  
     6  ## Know Your Template Functions
     7  
     8  Helm uses [Go templates](https://godoc.org/text/template) for templating
     9  your resource files. While Go ships several built-in functions, we have
    10  added many others.
    11  
    12  First, we added almost all of the functions in the
    13  [Sprig library](https://godoc.org/github.com/Masterminds/sprig). We removed two
    14  for security reasons: `env` and `expandenv` (which would have given chart authors
    15  access to Tiller's environment).
    16  
    17  We also added two special template functions: `include` and `required`. The `include`
    18  function allows you to bring in another template, and then pass the results to other
    19  template functions.
    20  
    21  For example, this template snippet includes a template called `mytpl`, then
    22  lowercases the result, then wraps that in double quotes.
    23  
    24  ```yaml
    25  value: {{ include "mytpl" . | lower | quote }}
    26  ```
    27  
    28  The `required` function allows you to declare a particular
    29  values entry as required for template rendering. If the value is empty, the template
    30  rendering will fail with a user submitted error message.
    31  
    32  The following example of the `required` function declares an entry for .Values.who
    33  is required, and will print an error message when that entry is missing:
    34  
    35  ```yaml
    36  value: {{ required "A valid .Values.who entry required!" .Values.who }}
    37  ```
    38  
    39  ## Quote Strings, Don't Quote Integers
    40  
    41  When you are working with string data, you are always safer quoting the
    42  strings than leaving them as bare words:
    43  
    44  ```yaml
    45  name: {{ .Values.MyName | quote }}
    46  ```
    47  
    48  But when working with integers _do not quote the values._ That can, in
    49  many cases, cause parsing errors inside of Kubernetes.
    50  
    51  ```yaml
    52  port: {{ .Values.Port }}
    53  ```
    54  
    55  This remark does not apply to env variables values which are expected to be string, even if they represent integers:
    56  
    57  ```yaml
    58  env:
    59    -name: HOST
    60      value: "http://host"
    61    -name: PORT
    62      value: "1234"
    63  ```
    64  
    65  ## Using the 'include' Function
    66  
    67  Go provides a way of including one template in another using a built-in
    68  `template` directive. However, the built-in function cannot be used in
    69  Go template pipelines.
    70  
    71  To make it possible to include a template, and then perform an operation
    72  on that template's output, Helm has a special `include` function:
    73  
    74  ```gotpl
    75  {{- include "toYaml" $value | nindent 2 }}
    76  ```
    77  
    78  The above includes a template called `toYaml`, passes it `$value`, and
    79  then passes the output of that template to the `nindent` function. Using
    80  the `{{- ... | nindent _n_ }}` pattern makes it easier to read the `include`
    81  in context, because it chomps the whitespace to the left (including the
    82  previous newline), then the `nindent` re-adds the newline and indents
    83  the included content by the requested amount.
    84  
    85  Because YAML ascribes significance to indentation levels and whitespace,
    86  this is one great way to include snippets of code, but handle
    87  indentation in a relevant context.
    88  
    89  ## Using the 'required' function
    90  
    91  Go provides a way for setting template options to control behavior
    92  when a map is indexed with a key that's not present in the map. This
    93  is typically set with template.Options("missingkey=option"), where option
    94  can be default, zero, or error. While setting this option to error will
    95  stop execution with an error, this would apply to every missing key in the
    96  map. There may be situations where a chart developer wants to enforce this
    97  behavior for select values in the values.yml file.
    98  
    99  The `required` function gives developers the ability to declare a value entry
   100  as required for template rendering. If the entry is empty in values.yml, the
   101  template will not render and will return an error message supplied by the
   102  developer.
   103  
   104  For example:
   105  
   106  ```gotpl
   107  {{ required "A valid foo is required!" .Values.foo }}
   108  ```
   109  
   110  The above will render the template when .Values.foo is defined, but will fail
   111  to render and exit when .Values.foo is undefined.
   112  
   113  ## Using the 'tpl' Function
   114  
   115  The `tpl` function allows developers to evaluate strings as templates inside a template.
   116  This is useful to pass a template string as a value to a chart or render external configuration files.
   117  Syntax: `{{ tpl TEMPLATE_STRING VALUES }}`
   118  
   119  Examples:
   120  
   121  ```yaml
   122  # values
   123  template: "{{ .Values.name }}"
   124  name: "Tom"
   125  
   126  # template
   127  {{ tpl .Values.template . }}
   128  
   129  # output
   130  Tom
   131  ```
   132  
   133  Rendering a external configuration file:
   134  
   135  ```yaml
   136  # external configuration file conf/app.conf
   137  firstName={{ .Values.firstName }}
   138  lastName={{ .Values.lastName }}
   139  
   140  # values
   141  firstName: Peter
   142  lastName: Parker
   143  
   144  # template
   145  {{ tpl (.Files.Get "conf/app.conf") . }}
   146  
   147  # output
   148  firstName=Peter
   149  lastName=Parker
   150  ```
   151  
   152  ## Creating Image Pull Secrets
   153  
   154  Image pull secrets are essentially a combination of _registry_, _username_, and _password_. You may need them in an application you are deploying, but to create them requires running _base64_ a couple of times. We can write a helper template to compose the Docker configuration file for use as the Secret's payload. Here is an example:
   155  
   156  First, assume that the credentials are defined in the `values.yaml` file like so:
   157  
   158  ```yaml
   159  imageCredentials:
   160    registry: quay.io
   161    username: someone
   162    password: sillyness
   163  ```
   164  
   165  We then define our helper template as follows:
   166  
   167  ```gotpl
   168  {{- define "imagePullSecret" }}
   169  {{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }}
   170  {{- end }}
   171  ```
   172  
   173  Finally, we use the helper template in a larger template to create the Secret manifest:
   174  
   175  ```yaml
   176  apiVersion: v1
   177  kind: Secret
   178  metadata:
   179    name: myregistrykey
   180  type: kubernetes.io/dockerconfigjson
   181  data:
   182    .dockerconfigjson: {{ template "imagePullSecret" . }}
   183  ```
   184  
   185  ## Automatically Roll Deployments When ConfigMaps or Secrets change
   186  
   187  Often times configmaps or secrets are injected as configuration
   188  files in containers.
   189  Depending on the application a restart may be required should those
   190  be updated with a subsequent `helm upgrade`, but if the
   191  deployment spec itself didn't change the application keeps running
   192  with the old configuration resulting in an inconsistent deployment.
   193  
   194  The `sha256sum` function can be used to ensure a deployment's
   195  annotation section is updated if another file changes:
   196  
   197  ```yaml
   198  kind: Deployment
   199  spec:
   200    template:
   201      metadata:
   202        annotations:
   203          checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
   204  [...]
   205  ```
   206  
   207  See also the `helm upgrade --recreate-pods` flag for a slightly
   208  different way of addressing this issue.
   209  
   210  ## Tell Tiller Not To Delete a Resource
   211  
   212  Sometimes there are resources that should not be deleted when Helm runs a
   213  `helm delete`. Chart developers can add an annotation to a resource to prevent
   214  it from being deleted.
   215  
   216  ```yaml
   217  kind: Secret
   218  metadata:
   219    annotations:
   220      "helm.sh/resource-policy": keep
   221  [...]
   222  ```
   223  
   224  (Quotation marks are required)
   225  
   226  The annotation `"helm.sh/resource-policy": keep` instructs Tiller to skip this
   227  resource during a `helm delete` operation. _However_, this resource becomes
   228  orphaned. Helm will no longer manage it in any way. This can lead to problems
   229  if using `helm install --replace` on a release that has already been deleted, but
   230  has kept resources.
   231  
   232  ## Using "Partials" and Template Includes
   233  
   234  Sometimes you want to create some reusable parts in your chart, whether
   235  they're blocks or template partials. And often, it's cleaner to keep
   236  these in their own files.
   237  
   238  In the `templates/` directory, any file that begins with an
   239  underscore(`_`) is not expected to output a Kubernetes manifest file. So
   240  by convention, helper templates and partials are placed in a
   241  `_helpers.tpl` file.
   242  
   243  ## Complex Charts with Many Dependencies
   244  
   245  Many of the charts in the [official charts repository](https://github.com/helm/charts)
   246  are "building blocks" for creating more advanced applications. But charts may be
   247  used to create instances of large-scale applications. In such cases, a single
   248  umbrella chart may have multiple subcharts, each of which functions as a piece
   249  of the whole.
   250  
   251  The current best practice for composing a complex application from discrete parts
   252  is to create a top-level umbrella chart that
   253  exposes the global configurations, and then use the `charts/` subdirectory to
   254  embed each of the components.
   255  
   256  Two strong design patterns are illustrated by these projects:
   257  
   258  **SAP's [OpenStack chart](https://github.com/sapcc/openstack-helm):** This chart
   259  installs a full OpenStack IaaS on Kubernetes. All of the charts are collected
   260  together in one GitHub repository.
   261  
   262  **Deis's [Workflow](https://github.com/deis/workflow/tree/master/charts/workflow):**
   263  This chart exposes the entire Deis PaaS system with one chart. But it's different
   264  from the SAP chart in that this umbrella chart is built from each component, and
   265  each component is tracked in a different Git repository. Check out the
   266  `requirements.yaml` file to see how this chart is composed by their CI/CD
   267  pipeline.
   268  
   269  Both of these charts illustrate proven techniques for standing up complex environments
   270  using Helm.
   271  
   272  ## YAML is a Superset of JSON
   273  
   274  According to the YAML specification, YAML is a superset of JSON. That
   275  means that any valid JSON structure ought to be valid in YAML.
   276  
   277  This has an advantage: Sometimes template developers may find it easier
   278  to express a datastructure with a JSON-like syntax rather than deal with
   279  YAML's whitespace sensitivity.
   280  
   281  As a best practice, templates should follow a YAML-like syntax _unless_
   282  the JSON syntax substantially reduces the risk of a formatting issue.
   283  
   284  ## Be Careful with Generating Random Values
   285  
   286  There are functions in Helm that allow you to generate random data,
   287  cryptographic keys, and so on. These are fine to use. But be aware that
   288  during upgrades, templates are re-executed. When a template run
   289  generates data that differs from the last run, that will trigger an
   290  update of that resource.
   291  
   292  ## Upgrade a release idempotently
   293  
   294  In order to use the same command when installing and upgrading a release, use the following command:
   295  
   296  ```shell
   297  helm upgrade --install <release name> --values <values file> <chart directory>
   298  ```