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

PatternExample
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

PatternUse
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

PracticeReason
Prefer include over templatePipeable; can be combined with nindent
Pass dict contextExplicit scope avoids surprises
Centralize labels/selectorsAvoid drift across resources

9. Handling Edge Cases

CasePattern
Nil map traversalUse with or default
Empty list{{- if .Values.list }}
Missing key with dashes{{ index .Values "weird-key" | default "" }}
Type coercion{{ .Values.x | toString }}

10. Creating Maintainable Templates