Implementing Chart Best Practices

1. Following Naming Conventions

ElementConvention
Chart namelowercase, hyphens; matches directory
Values keyscamelCase
Template helperschartname.purpose (dot-prefixed)
Resource namesUse 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

AnnotationPurpose
checksum/configForce pod restart on ConfigMap change
helm.sh/hookMark resource as install/upgrade hook
helm.sh/resource-policy: keepRetain on uninstall
Prometheus scrapeprometheus.io/scrape: "true"

5. Making Charts Configurable

6. Providing Sensible Defaults

SettingSensible default
replicaCount1 (scale up explicitly)
resourcesEmpty {} — let user opt in
service.typeClusterIP
ingress.enabledfalse
securityContextNon-root + drop ALL capabilities

7. Documenting Chart Usage

DocTool
READMEhelm-docs auto-generates from values comments
values.yaml comments# -- description for helm-docs
Schemavalues.schema.json doubles as documentation
Examplesexamples/ 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