Lesson 18 / 25

Chart Best Practices

Write charts that are predictable, portable and easy to operate.

Conventions that save pain later

A good chart follows a few conventions. Use the recommended labels app.kubernetes.io/name, instance, version, component, part-of and managed-by, keeping selectors to the stable subset. Do not hardcode metadata.namespace in templates; let --namespace decide (or use .Release.Namespace consistently). Give every container resource requests, probes and a restrictive securityContext (runAsNonRoot, readOnlyRootFilesystem, dropped capabilities), with values to override them. Make optional features opt-in with enabled flags and keep values flat and documented, with comments above each key; tools such as helm-docs turn those comments into a README table. Name values in camelCase, starting lowercase. Avoid giant charts that template every Kubernetes field: expose what users truly need, and offer extraEnv, extraVolumes or podAnnotations escape hatches for the rest.

A documented, secure-by-default values block

Comments double as documentation; defaults are safe, overrides are possible.

# -- Number of pods when autoscaling is disabled
replicaCount: 2

# -- Container security settings (secure defaults)
securityContext:
  runAsNonRoot: true
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

# -- Liveness and readiness probes
probes:
  readiness: { httpGet: { path: /healthz/ready, port: http }, periodSeconds: 5 }
  liveness:  { httpGet: { path: /healthz/live,  port: http }, periodSeconds: 10 }

# -- Extra environment variables appended to the container
extraEnv: []

Design for the person upgrading

Renaming a value or a resource breaks every user's upgrade. Deprecate old keys gracefully (support both for a release and fail with a helpful required/fail message later) and document breaking changes in the chart's changelog with a major version bump.

Quick check: Which practice keeps a chart portable across namespaces?

  • Letting the release namespace decide instead of hardcoding it
  • Hardcoding metadata.namespace: production
  • Putting every value under global
  • Using the template action instead of include
Answer

Letting the release namespace decide instead of hardcoding it — Hardcoded namespaces break installs into other namespaces and confuse Helm's release tracking.