Creating Template Files

1. Understanding Template Syntax

DelimiterPurpose
{{ ... }}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 }}
HelperUse
toYamlMarshal map/list to YAML
nindent NNewline + 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 }}

10. Using Template Comments ({{/* */}})

FormBehavior
{{/* comment */}}Removed during render; leaves no blank lines
# yaml commentSurvives 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.