Helm Chart Quick Reference
Version: 1.0.0 | Target Size: <100KB | Purpose: Fast reference for Helm chart development and deployment
Overview
Helm is a package manager for Kubernetes that simplifies application deployment through charts - pre-configured Kubernetes resource templates. This quick reference provides essential patterns for chart creation, templating, and deployment.
When to Load This Skill:
- •Detected:
Chart.yaml,values.yaml,templates/directory - •Manual:
--tools=helmflag - •Use Case: Kubernetes application packaging and deployment
Progressive Disclosure:
- •This file (SKILL.md): Quick reference for immediate use
- •REFERENCE.md: Comprehensive guide with advanced patterns and 10+ production examples
Table of Contents
- •Chart Structure
- •Chart.yaml Configuration
- •Template Syntax Quick Reference
- •Values File Patterns
- •Common Helm Commands
- •Dependency Management
- •Release Lifecycle
- •Testing with Helm
- •Security Best Practices
- •Quick Examples
Chart Structure
Standard Helm chart directory layout:
mychart/ ├── Chart.yaml # Chart metadata (name, version, description) ├── values.yaml # Default configuration values ├── charts/ # Chart dependencies (subcharts) ├── templates/ # Kubernetes manifest templates │ ├── NOTES.txt # Post-install usage notes │ ├── _helpers.tpl # Named templates (partials) │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── configmap.yaml │ └── secret.yaml ├── .helmignore # Files to exclude from packaging └── README.md # Chart documentation
Key Concepts:
- •Chart.yaml: Defines chart metadata (name, version, dependencies)
- •values.yaml: Default configuration values (can be overridden)
- •templates/: Go templates that render to Kubernetes manifests
- •charts/: Dependency charts (populated by
helm dependency update)
Chart.yaml Configuration
Chart.yaml defines chart metadata and dependencies:
apiVersion: v2 # Helm 3 uses v2
name: webapp # Chart name (DNS-compatible)
version: 1.2.3 # Chart version (SemVer)
appVersion: "2.0.1" # Application version
description: Production web application with autoscaling
type: application # application or library
keywords:
- webapp
- kubernetes
- production
home: https://example.com
sources:
- https://github.com/example/webapp
maintainers:
- name: DevOps Team
email: devops@example.com
dependencies:
- name: postgresql
version: "12.1.0"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled # Optional: conditional dependency
- name: redis
version: "17.3.0"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
Version Guidelines:
- •Chart version: Increment when chart templates/structure changes
- •appVersion: Application/container image version (independent of chart version)
- •Use Semantic Versioning: MAJOR.MINOR.PATCH
Dependency Types:
- •Condition: Enable/disable via values (
postgresql.enabled: true) - •Tags: Group dependencies (
--set tags.database=false) - •Import-values: Import child chart values into parent
Template Syntax Quick Reference
Helm uses Go templates with additional functions.
Built-in Objects
# Access values from values.yaml
{{ .Values.replicaCount }}
{{ .Values.image.repository }}
{{ .Values.service.port }}
# Release information
{{ .Release.Name }} # Release name (helm install <name>)
{{ .Release.Namespace }} # Kubernetes namespace
{{ .Release.IsInstall }} # true if installing (not upgrading)
{{ .Release.IsUpgrade }} # true if upgrading
{{ .Release.Revision }} # Revision number
# Chart metadata (from Chart.yaml)
{{ .Chart.Name }}
{{ .Chart.Version }}
{{ .Chart.AppVersion }}
# Kubernetes cluster capabilities
{{ .Capabilities.APIVersions.Has "apps/v1" }}
{{ .Capabilities.KubeVersion.Major }}
{{ .Capabilities.KubeVersion.Minor }}
# Template context
{{ .Template.Name }} # Current template file name
{{ .Template.BasePath }} # Template directory path
Control Structures
# If/Else conditionals
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
# ... ingress spec
{{- end }}
# If/Else with multiple conditions
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
# Create new PVC
{{- else if .Values.persistence.existingClaim }}
# Use existing PVC
{{- else }}
# Use emptyDir
{{- end }}
# Range (loops)
{{- range .Values.extraEnv }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
# Range with key-value pairs
{{- range $key, $value := .Values.config }}
{{ $key }}: {{ $value | quote }}
{{- end }}
# With (scope modification)
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 2 }}
{{- end }}
Template Functions
String Functions:
{{ .Values.name | quote }} # "webapp"
{{ .Values.name | upper }} # WEBAPP
{{ .Values.name | lower }} # webapp
{{ .Values.name | title }} # Webapp
{{ .Values.name | trim }} # Remove whitespace
{{ .Values.name | trunc 10 }} # Truncate to 10 chars
{{ .Values.name | default "default" }} # Default if empty
Type Conversion:
{{ .Values.port | toString }} # Convert to string
{{ .Values.replicas | int }} # Convert to integer
{{ .Values.enabled | ternary "yes" "no" }} # Conditional value
Encoding:
{{ .Values.config | b64enc }} # Base64 encode
{{ .Values.secret | b64dec }} # Base64 decode
{{ .Values.data | toJson }} # Convert to JSON
{{ .Values.data | toYaml }} # Convert to YAML
Lists and Dictionaries:
{{ .Values.list | first }} # First element
{{ .Values.list | rest }} # All but first
{{ .Values.list | last }} # Last element
{{ .Values.list | has "item" }} # Check if contains
{{ .Values.dict | keys }} # Dictionary keys
{{ .Values.dict | values }} # Dictionary values
Kubernetes-Specific:
{{ include "mychart.labels" . | nindent 4 }} # Include named template with indent
{{ .Values.resources | toYaml | nindent 8 }} # Convert resources to YAML
{{ .Release.Name | trunc 63 | trimSuffix "-" }} # DNS-safe name (≤63 chars)
Named Templates (Helpers)
Define in templates/_helpers.tpl:
{{/*
Expand the name of the chart.
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a fully qualified app name.
*/}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- 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
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
Use in templates:
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
Values File Patterns
values.yaml provides default configuration values:
# Replica configuration
replicaCount: 3
# Image configuration
image:
repository: myapp
pullPolicy: IfNotPresent
tag: "" # Defaults to .Chart.AppVersion
# Image pull secrets
imagePullSecrets:
- name: regcred
# Service account
serviceAccount:
create: true
annotations: {}
name: ""
# Pod annotations
podAnnotations: {}
# Pod security context
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
# Container security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Service configuration
service:
type: ClusterIP
port: 80
targetPort: 8080
# Ingress configuration
ingress:
enabled: false
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: example-tls
hosts:
- example.com
# Resources
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# Autoscaling
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
# Node selector
nodeSelector: {}
# Tolerations
tolerations: []
# Affinity
affinity: {}
# Persistence
persistence:
enabled: true
storageClass: "gp3"
size: 10Gi
accessMode: ReadWriteOnce
# Environment variables
env:
- name: APP_ENV
value: production
- name: LOG_LEVEL
value: info
# ConfigMap data
config:
database_host: postgres.default.svc.cluster.local
database_port: "5432"
cache_ttl: "3600"
# Secrets (base64 encoded)
secrets:
database_password: "" # Override at install time
Environment-Specific Overrides:
# Development values (values-dev.yaml)
replicaCount: 1
resources:
limits:
cpu: 200m
memory: 256Mi
# Production values (values-prod.yaml)
replicaCount: 5
resources:
limits:
cpu: 1000m
memory: 1Gi
autoscaling:
enabled: true
maxReplicas: 20
Common Helm Commands
Chart Creation
# Create new chart helm create mychart # Validate chart structure helm lint mychart/ # Package chart into archive helm package mychart/ # Output: mychart-1.0.0.tgz # Render templates locally (dry-run) helm template myrelease mychart/ helm template myrelease mychart/ --values values-prod.yaml # Show computed values helm show values mychart/
Release Management
# Install chart helm install myrelease mychart/ helm install myrelease mychart/ --namespace production --create-namespace # Install with custom values helm install myrelease mychart/ --values values-prod.yaml helm install myrelease mychart/ --set replicaCount=5 --set image.tag=v2.0.0 # Dry-run installation (validate without installing) helm install myrelease mychart/ --dry-run --debug # Upgrade release helm upgrade myrelease mychart/ helm upgrade myrelease mychart/ --values values-prod.yaml --set image.tag=v2.1.0 # Upgrade or install (install if doesn't exist) helm upgrade --install myrelease mychart/ # Rollback to previous revision helm rollback myrelease helm rollback myrelease 3 # Rollback to specific revision # Uninstall release helm uninstall myrelease helm uninstall myrelease --namespace production # Keep history after uninstall helm uninstall myrelease --keep-history
Release Information
# List releases helm list helm list --namespace production helm list --all-namespaces # Show release status helm status myrelease # Show release history helm history myrelease # Get release values helm get values myrelease helm get values myrelease --revision 3 # Get release manifest helm get manifest myrelease # Get all release information helm get all myrelease
Chart Repository
# Add repository helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add stable https://charts.helm.sh/stable # Update repositories helm repo update # Search repositories helm search repo postgresql helm search repo bitnami/postgresql --versions # Show chart information helm show chart bitnami/postgresql helm show values bitnami/postgresql helm show readme bitnami/postgresql
Dependencies
# Update chart dependencies helm dependency update mychart/ # List dependencies helm dependency list mychart/ # Build dependencies (download to charts/ directory) helm dependency build mychart/
Dependency Management
Declaring Dependencies (Chart.yaml)
dependencies:
# Database dependency
- name: postgresql
version: "12.1.0"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
tags:
- database
# Cache dependency
- name: redis
version: "17.3.0"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
tags:
- cache
# Local chart dependency
- name: common
version: "1.0.0"
repository: file://../common
Managing Dependency Values
Parent chart values.yaml:
# Configure postgresql subchart
postgresql:
enabled: true
auth:
username: myapp
password: changeme
database: myapp_production
primary:
persistence:
enabled: true
size: 20Gi
# Configure redis subchart
redis:
enabled: true
auth:
enabled: false
master:
persistence:
enabled: false
Conditional Dependencies
# Enable/disable dependencies helm install myrelease mychart/ \ --set postgresql.enabled=true \ --set redis.enabled=false # Using tags helm install myrelease mychart/ \ --set tags.database=true \ --set tags.cache=false
Import Values from Dependencies
Chart.yaml:
dependencies:
- name: postgresql
version: "12.1.0"
repository: https://charts.bitnami.com/bitnami
import-values:
- child: auth.password
parent: dbPassword
Access in templates:
env:
- name: DB_PASSWORD
value: {{ .Values.dbPassword }}
Release Lifecycle
Installation Workflow
# 1. Dry-run to validate helm install myrelease mychart/ --dry-run --debug # 2. Install to staging helm install myrelease mychart/ \ --namespace staging \ --create-namespace \ --values values-staging.yaml # 3. Verify installation helm status myrelease --namespace staging kubectl get pods --namespace staging # 4. Promote to production helm install myrelease mychart/ \ --namespace production \ --create-namespace \ --values values-prod.yaml
Upgrade Workflow
# 1. Check current values helm get values myrelease --namespace production # 2. Dry-run upgrade helm upgrade myrelease mychart/ \ --namespace production \ --values values-prod.yaml \ --set image.tag=v2.1.0 \ --dry-run --debug # 3. Perform upgrade helm upgrade myrelease mychart/ \ --namespace production \ --values values-prod.yaml \ --set image.tag=v2.1.0 # 4. Monitor rollout kubectl rollout status deployment/myrelease-webapp --namespace production # 5. Verify upgrade helm status myrelease --namespace production
Rollback Workflow
# 1. Check release history helm history myrelease --namespace production # 2. Rollback to previous version helm rollback myrelease --namespace production # 3. Rollback to specific revision helm rollback myrelease 3 --namespace production # 4. Verify rollback helm status myrelease --namespace production kubectl rollout status deployment/myrelease-webapp --namespace production
Cleanup
# Uninstall release (removes all resources) helm uninstall myrelease --namespace production # Keep history (allows rollback after uninstall) helm uninstall myrelease --namespace production --keep-history # Delete namespace kubectl delete namespace production
Testing with Helm
Lint Validation
# Lint chart for issues helm lint mychart/ # Lint with custom values helm lint mychart/ --values values-prod.yaml # Strict linting (fail on warnings) helm lint mychart/ --strict
Common lint issues:
- •Chart.yaml missing required fields
- •Invalid YAML syntax in templates
- •Missing
{{ required }}for critical values - •Chart version not following SemVer
Template Validation
# Render templates locally helm template myrelease mychart/ # Render with custom values helm template myrelease mychart/ --values values-prod.yaml # Debug template rendering helm template myrelease mychart/ --debug # Validate against Kubernetes API helm template myrelease mychart/ | kubectl apply --dry-run=client -f -
Helm Tests
Create test pod (templates/tests/test-connection.yaml):
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "mychart.fullname" . }}-test-connection"
labels:
{{- include "mychart.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test # Mark as test hook
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "mychart.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
Run tests:
# Run all tests for release helm test myrelease --namespace production # Show test logs helm test myrelease --namespace production --logs # Cleanup test pods after run kubectl delete pod -l 'helm.sh/hook=test' --namespace production
Security Best Practices
1. Image Security
# Pin specific image versions (avoid :latest) image: repository: myapp tag: "v2.1.0" # Explicit version pullPolicy: IfNotPresent # Use SHA256 digests for immutability image: repository: myapp digest: "sha256:abc123..." # Immutable image
2. RBAC Configuration
# Create minimal service account
serviceAccount:
create: true
annotations:
# AWS IRSA example
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
name: ""
# Define RBAC role (templates/role.yaml)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "mychart.fullname" . }}
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
3. Pod Security
# Pod security context
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
# Container security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 1000
4. Secrets Management
# Use Kubernetes Secrets (not ConfigMaps)
apiVersion: v1
kind: Secret
metadata:
name: {{ include "mychart.fullname" . }}
type: Opaque
data:
# Base64 encoded values
database-password: {{ .Values.secrets.databasePassword | b64enc | quote }}
# Reference secrets in pods
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "mychart.fullname" . }}
key: database-password
External Secrets Integration:
# Use External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ include "mychart.fullname" . }}
spec:
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: {{ include "mychart.fullname" . }}-secrets
data:
- secretKey: database-password
remoteRef:
key: /prod/myapp/db-password
5. Network Policies
# Restrict pod network access
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "mychart.fullname" . }}
spec:
podSelector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: {{ .Values.service.targetPort }}
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
{{- end }}
6. Resource Limits
# Always set resource limits
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
7. Required Values Validation
# Force required values at install time
{{- if not .Values.secrets.databasePassword }}
{{- fail "secrets.databasePassword is required" }}
{{- end }}
# Or use required function
database:
password: {{ required "Database password required" .Values.secrets.databasePassword }}
Quick Examples
Minimal Web Application Chart
Chart.yaml:
apiVersion: v2 name: webapp version: 1.0.0 appVersion: "1.0" description: Simple web application
values.yaml:
replicaCount: 2 image: repository: nginx tag: "1.21" service: port: 80
templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: webapp
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 80
templates/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}
spec:
type: ClusterIP
ports:
- port: {{ .Values.service.port }}
targetPort: 80
selector:
app: {{ .Release.Name }}
Install:
helm install myapp webapp/
Next Steps
For Advanced Patterns:
- •See REFERENCE.md for comprehensive guide with 10+ production examples
- •Covers: Hooks, CI/CD integration, OCI registries, testing strategies
Common Use Cases:
- •Multi-environment deployments → REFERENCE.md § CI/CD Integration
- •Chart testing → REFERENCE.md § Testing Strategies
- •Complex dependencies → REFERENCE.md § Dependencies Deep Dive
- •Production patterns → REFERENCE.md § Production Examples
Progressive Disclosure: Start here for quick reference, load REFERENCE.md for comprehensive patterns and production examples.
Performance Target: <100ms skill loading (this file ~75KB)
Last Updated: 2025-10-23 | Version: 1.0.0