Creating Template Files
1. Understanding Template Syntax
| Delimiter | Purpose |
{{ ... }} | Action (expression / function call) |
{{- ... -}} | Trim whitespace left/right |
{{/* ... */}} | Template comment (not rendered) |
{{ .Values.x }} | Access values |
{{ include "name" . }} | Render a named template |
2. Creating Deployment Template
Example: Standard Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels: {{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels: {{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels: {{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort | default 8080 }}
resources: {{- toYaml .Values.resources | nindent 12 }}
3. Creating Service Template
Example: ClusterIP Service
apiVersion: v1
kind: Service
metadata:
name: {{ include "myapp.fullname" . }}
labels: {{- include "myapp.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector: {{- include "myapp.selectorLabels" . | nindent 4 }}
4. Creating ConfigMap Template
Example: App configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "myapp.fullname" . }}-config
data:
app.yaml: |
{{- toYaml .Values.appConfig | nindent 4 }}
log_level: {{ .Values.logLevel | quote }}
| Helper | Use |
toYaml | Marshal map/list to YAML |
nindent N | Newline + indent N spaces |
5. Creating Secret Template
Example: Encoded Secret
apiVersion: v1
kind: Secret
metadata:
name: {{ include "myapp.fullname" . }}-secret
type: Opaque
data:
password: {{ .Values.dbPassword | b64enc | quote }}
stringData:
apiKey: {{ .Values.apiKey | quote }}
Warning: Never commit plaintext secrets to values.yaml. Use external secret stores or --set from CI vault integration.
6. Creating Ingress Template
Example: Conditional Ingress
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "myapp.fullname" . }}
annotations: {{- toYaml .Values.ingress.annotations | nindent 4 }}
spec:
ingressClassName: {{ .Values.ingress.className }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "myapp.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
7. Creating ServiceAccount Template
Example: Optional SA
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "myapp.serviceAccountName" . }}
labels: {{- include "myapp.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount | default false }}
{{- end }}
8. Creating RBAC Templates
Example: Role + RoleBinding
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "myapp.fullname" . }}
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "myapp.fullname" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "myapp.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "myapp.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
9. Creating PersistentVolumeClaim Template
Example: PVC
{{- if .Values.persistence.enabled -}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "myapp.fullname" . }}-data
spec:
accessModes: {{- toYaml .Values.persistence.accessModes | nindent 4 }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- with .Values.persistence.storageClassName }}
storageClassName: {{ . | quote }}
{{- end }}
{{- end }}
| Form | Behavior |
{{/* comment */}} | Removed during render; leaves no blank lines |
# yaml comment | Survives rendering; visible in helm template output |
11. Using Multi-Document Templates
Example: Multiple resources per file
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "myapp.fullname" . }}-a
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "myapp.fullname" . }}-b
Note: Document separator --- must be at column 0 and not inside a string.