The Ops Community ⚙️

Lucy Linder
Lucy Linder

Posted on • Edited on • Originally published at blog.derlin.ch

Helm templates: do not use tpl in vain

From the documentation:

The tpl function allows developers to evaluate strings as templates inside a template. This is useful to pass a template string as a value to a chart or render external configuration files. Syntax: {{ tpl TEMPLATE_STRING VALUES }}

When writing generic Helm charts or libraries, calls to tpl are often overused, and for a good reason: they give lots of flexibility, and allow chart users to avoid repetition in the values.yaml file.

The tpl function is however costly, and slow, and this is why it should be called only when necessary.

`tpl` function not performant #8002

I have a scenario of having one umbrella chart with many sub-charts as dependencies. When I have the templates folder in umbrella chart, helm lint takes more time like almost 30 to 40 minutes. When this folder is not there, helm lint returns very fast. Can I know the reason.running in debug mode not giving any logs. It is helm v3.

How to limit calls while keeping the flexibility ? My solution is to wrap all calls to tpl using the following helper function:

{{- define "bettertpl" -}}
  {{- $tpl := .value -}}
  {{- /* handle cases where .value is a yaml object */ -}}
  {{- if not (typeIs "string" $tpl) -}}
    {{- $tpl = toYaml $tpl -}}
  {{- end -}}
  {{- /* only call tpl if there is at least one template expression */ -}}
  {{- if contains "{{" $tpl -}}
    {{- tpl $tpl .context }}
  {{- else -}}
    {{- $tpl -}}
  {{- end -}}
{{- end -}}
Enter fullscreen mode Exit fullscreen mode

As the code should make it clear, bettertpl adds two features to the regular tpl:

  1. it allows to template anything (not just string), as dict, list, etc. will be converted to string first, and
  2. it only calls the slow tpl when needed: if the string doesn't contain at least one {{ ... }}, we know we can just print it as is.

Usage:

before: {{ tpl .Values.foo . }}
after: {{ include "bettertpl" (dict "value" .Values.foo "context" .) }}
Enter fullscreen mode Exit fullscreen mode

You find it too verbose ?

Note that I use named arguments for better readability. You can get rid of them and use lists instead:

{{ include "bettertpl" (list .Values.foo .) }}
Enter fullscreen mode Exit fullscreen mode

In the template above, change .valuefirst . and .contextindex . 2 to read from list arguments instead.



Is it worth it ? As an example, I recently migrated a gitops repository with an umbrella chart of around 20 sub-charts. After a refactoring allowing me to use only one base chart for all, my helm template went from <1s to more than 15 seconds...

I was able to take it down to 4 seconds by limiting the calls to tpl with this simple trick, which is quite an improvement.

Top comments (0)