| name | helm-chart |
| description | Generate production-ready Helm charts following official best practices. Use when creating Kubernetes Helm charts, chart templates, values.yaml files, or _helpers.tpl. Triggers on requests for Helm chart generation, Kubernetes packaging, or chart template development. |
Helm Chart Generation
Generate production-ready Helm charts following official Helm best practices.
Chart Structure
mychart/
├── Chart.yaml # Required: chart metadata
├── values.yaml # Default configuration values
├── charts/ # Dependencies
├── crds/ # CRD definitions (not templated)
├── templates/
│ ├── NOTES.txt # Post-install instructions
│ ├── _helpers.tpl # Template helpers
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ └── tests/
│ └── test-connection.yaml
└── .helmignore
Naming Conventions
Chart names: lowercase letters, numbers, hyphens only. Start with letter.
✓ nginx-ingress, aws-cluster-autoscaler
✗ Nginx_Ingress, 1st-chart
Template files: dashed notation, reflect resource kind.
✓ foo-deployment.yaml, bar-svc.yaml
✗ fooDeployment.yaml, bar.yaml
Values: camelCase, lowercase start. No hyphens.
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
ReplicaCount: 1
replica-count: 1
Template Formatting
{{ .Values.foo }}
{{.Values.foo}}
{{- if .Values.enabled }}
key: value
{{- end }}
Essential _helpers.tpl
{{/*
Chart name, truncated to 63 chars (DNS limit)
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Fully qualified app name. Release + chart name, max 63 chars.
*/}}
{{- define "mychart.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 }}
{{/*
Common labels
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels (immutable for Deployments)
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Chart label
*/}}
{{- define "mychart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
ServiceAccount name
*/}}
{{- define "mychart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "mychart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Labels vs Annotations
Labels: For identification and querying. Used by Kubernetes selectors.
Annotations: For non-identifying metadata. Not used for selection.
Standard Labels
| Label | Status | Description |
|---|
app.kubernetes.io/name | REC | App name: {{ template "name" . }} |
app.kubernetes.io/instance | REC | Release: {{ .Release.Name }} |
app.kubernetes.io/version | OPT | App version: {{ .Chart.AppVersion }} |
app.kubernetes.io/managed-by | REC | Always: {{ .Release.Service }} |
helm.sh/chart | REC | Chart identifier: {{ .Chart.Name }}-{{ .Chart.Version }} |
app.kubernetes.io/component | OPT | Role in app: frontend, backend, database |
app.kubernetes.io/part-of | OPT | Parent application name (for multi-chart apps) |
REC = Recommended (should always include), OPT = Optional
Values Best Practices
See references/values-patterns.md for comprehensive patterns from Bitnami, ArgoCD, Grafana charts.
When to Use Subtrees vs Flat Values
Subtrees for K8s API objects - Users toYaml entire sections:
resources: {}
podSecurityContext: {}
resourceLimitsCpu: 100m
resourceLimitsMemory: 128Mi
Flat for simple values:
replicaCount: 1
revisionHistoryLimit: 3
Empty Defaults {}
Allow users to override entire sections or leave empty:
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
Maps over Arrays (for --set compatibility)
servers:
foo:
port: 80
servers:
- name: foo
port: 80
Document Every Value
replicaCount: 1
image:
registry: docker.io
repository: nginx
tag: ""
Standard values.yaml Structure
Industry-standard structure (matches helm create + Bitnami patterns):
replicaCount: 1
revisionHistoryLimit: 3
image:
registry: docker.io
repository: nginx
tag: ""
pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
create: true
automount: true
annotations: {}
name: ""
podAnnotations: {}
podLabels: {}
podSecurityContext: {}
securityContext: {}
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
resources: {}
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 10
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
extraEnvVars: []
extraVolumes: []
extraVolumeMounts: []
Pattern: Subtrees for toYaml
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
Pattern: Enabled Flag + Config
metrics:
enabled: false
service:
port: 9090
serviceMonitor:
enabled: false
interval: 30s
{{- if .Values.metrics.enabled }}
{{- end }}
RBAC Pattern
rbac:
create: true
serviceAccount:
create: true
name: ""
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "mychart.serviceAccountName" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
Image Configuration Pattern
image:
repository: nginx
pullPolicy: IfNotPresent
tag: ""
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
Never use latest, head, canary tags.
PodTemplate Selector Pattern
Always declare explicit selectors (prevents breakage on label changes):
spec:
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "mychart.selectorLabels" . | nindent 8 }}
Flow Control
{{- if .Values.ingress.enabled }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
{{- end }}
{{- with .Values.favorite }}
release: {{ $.Release.Name }}
{{- end }}
Key Functions
See references/functions.md for full list. Most common:
| Function | Usage |
|---|
default | {{ .Values.name | default "app" }} |
quote | {{ .Values.env | quote }} |
toYaml | {{- toYaml .Values.resources | nindent 12 }} |
include | {{ include "mychart.name" . }} |
required | {{ required "msg" .Values.key }} |
tpl | {{ tpl .Values.template . }} |
lookup | {{ lookup "v1" "Secret" "ns" "name" }} |
Validation & Debugging
See references/validation.md for full validation pipeline with all tools.
Quick Validation
helm lint ./mychart --strict
helm template ./mychart --debug
helm template ./mychart | kubeconform -strict -summary -kubernetes-version 1.29.0
helm template ./mychart | pluto detect -
trivy config ./mychart --severity HIGH,CRITICAL
helm install --dry-run=server myrelease ./mychart
Debugging Tips
helm template --debug shows computed values
- Comment out broken sections, re-template to see rendered output
helm get manifest <release> shows what's actually deployed
- kubeconform
-ignore-missing-schemas skips unknown CRDs
Common Pitfalls
See references/common-pitfalls.md for detailed patterns. Key issues:
- Whitespace errors - use
{{- and -}} carefully
- Type coercion - quote strings, use
{{ int $val }} for numbers
- Nested value checks - each level needs existence check
- Selector immutability - don't include mutable labels in selectors
- YAML comments in templates -
# comments render, use {{/* */}} for template-only
Umbrella Charts
For multi-component applications, see references/umbrella-charts.md:
dependencies:
- name: frontend
version: "1.x.x"
repository: "file://charts/frontend"
- name: backend
version: "2.0.0"
repository: "https://charts.example.com"
condition: backend.enabled
helm dependency update ./myapp
References
| File | Content |
|---|
references/values-patterns.md | Industry-standard values.yaml patterns (Bitnami, ArgoCD, Grafana) |
references/functions.md | Go/Sprig/Helm function reference |
references/common-pitfalls.md | Template debugging patterns |
references/validation.md | Full validation pipeline (ct, kubeconform, trivy, pluto) |
references/umbrella-charts.md | Dependency management, multi-chart patterns |