Implementing Advanced Templating
1. Creating Recursive Templates
Example: Recursive label flattener
{{- define "flatten" -}}
{{- $prefix := .prefix -}}
{{- range $k, $v := .map -}}
{{- if kindIs "map" $v }}
{{- include "flatten" (dict "prefix" (printf "%s.%s" $prefix $k) "map" $v) -}}
{{- else }}
{{ $prefix }}.{{ $k }}: {{ $v | quote }}
{{- end -}}
{{- end -}}
{{- end -}}
2. Building Dynamic Names
Example: Name from values
{{- range .Values.regions }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ printf "%s-%s" (include "myapp.fullname" $) .name | trunc 63 | trimSuffix "-" }}
{{- end }}
3. Implementing Feature Flags
| Pattern | Example |
|---|---|
| Boolean toggle | {{- if .Values.features.metrics }} |
| Per-env | {{- if eq .Values.env "prod" }} |
| Capability gated | {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress" }} |
4. Creating Environment-Aware Templates
Example: Per-env resources
{{- $envCfg := index .Values.envs .Values.env -}}
resources:
requests:
cpu: {{ $envCfg.cpuRequest }}
memory: {{ $envCfg.memRequest }}
limits:
cpu: {{ $envCfg.cpuLimit }}
memory: {{ $envCfg.memLimit }}
5. Using Template Variables
| Pattern | Use |
|---|---|
| Cache expensive lookups | {{- $cm := lookup "v1" "ConfigMap" ... -}} |
| Reuse computed names | {{- $name := include "myapp.fullname" . -}} |
| Scope rebinding | {{ $root := . }}{{ range ... }}{{ $root.Values... }}{{ end }} |
6. Implementing Complex Data Structures
Example: Build dict dynamically
{{- $labels := dict -}}
{{- $_ := set $labels "app.kubernetes.io/name" (include "myapp.name" .) -}}
{{- $_ := set $labels "app.kubernetes.io/instance" .Release.Name -}}
{{- range $k, $v := .Values.extraLabels -}}
{{- $_ := set $labels $k $v -}}
{{- end }}
labels: {{- toYaml $labels | nindent 2 }}
7. Building Resource Templates Dynamically
Example: Many Services from one map
{{- range $name, $svc := .Values.services }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "myapp.fullname" $ }}-{{ $name }}
spec:
type: {{ $svc.type | default "ClusterIP" }}
ports:
{{- range $svc.ports }}
- name: {{ .name }}
port: {{ .port }}
targetPort: {{ .targetPort | default .port }}
{{- end }}
{{- end }}
8. Using Template Includes Efficiently
| Practice | Reason |
|---|---|
Prefer include over template | Pipeable; can be combined with nindent |
| Pass dict context | Explicit scope avoids surprises |
| Centralize labels/selectors | Avoid drift across resources |
9. Handling Edge Cases
| Case | Pattern |
|---|---|
| Nil map traversal | Use with or default |
| Empty list | {{- if .Values.list }} |
| Missing key with dashes | {{ index .Values "weird-key" | default "" }} |
| Type coercion | {{ .Values.x | toString }} |