Implementing Chart Best Practices
1. Following Naming Conventions
| Element | Convention |
| Chart name | lowercase, hyphens; matches directory |
| Values keys | camelCase |
| Template helpers | chartname.purpose (dot-prefixed) |
| Resource names | Use include "fullname" helper |
2. Using Fullname Templates
Example: Standard fullname helper
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
3. Implementing Proper Labels
Example: Standard label set
{{- define "myapp.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{ include "myapp.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{- define "myapp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myapp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
4. Using Annotations Appropriately
| Annotation | Purpose |
checksum/config | Force pod restart on ConfigMap change |
helm.sh/hook | Mark resource as install/upgrade hook |
helm.sh/resource-policy: keep | Retain on uninstall |
| Prometheus scrape | prometheus.io/scrape: "true" |
5. Making Charts Configurable
6. Providing Sensible Defaults
| Setting | Sensible default |
| replicaCount | 1 (scale up explicitly) |
| resources | Empty {} — let user opt in |
| service.type | ClusterIP |
| ingress.enabled | false |
| securityContext | Non-root + drop ALL capabilities |
7. Documenting Chart Usage
| Doc | Tool |
| README | helm-docs auto-generates from values comments |
| values.yaml comments | # -- description for helm-docs |
| Schema | values.schema.json doubles as documentation |
| Examples | examples/ dir with sample values files |
8. Creating Comprehensive NOTES.txt
Example: Helpful post-install message
Thanks for installing {{ .Chart.Name }} {{ .Chart.Version }}!
Get the application URL:
{{- if .Values.ingress.enabled }}
https://{{ (index .Values.ingress.hosts 0).host }}
{{- else if eq .Values.service.type "LoadBalancer" }}
kubectl get svc {{ include "myapp.fullname" . }} -n {{ .Release.Namespace }}
{{- else }}
kubectl port-forward svc/{{ include "myapp.fullname" . }} 8080:{{ .Values.service.port }}
{{- end }}
Verify pods are ready:
kubectl get pods -l app.kubernetes.io/instance={{ .Release.Name }} -n {{ .Release.Namespace }}
9. Implementing Resource Limits
Example: Always-set limits pattern
resources:
{{- toYaml .Values.resources | nindent 12 }}
# values.yaml
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 512Mi }
10. Using Health Checks
Example: All three probe types
startupProbe:
httpGet: { path: /healthz, port: http }
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet: { path: /healthz, port: http }
periodSeconds: 30
readinessProbe:
httpGet: { path: /ready, port: http }
periodSeconds: 10
11. Following Helm Chart Conventions