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