github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/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 ```