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 ```