Learn how to scaffold, understand, and deploy a Helm chart from scratch — from helm create through the full install/upgrade/rollback lifecycle.
The helm create command generates a complete, best-practice chart structure ready to customize.
# Create a new chart called "myapp"
helm create myapp
# What gets generated:
myapp/
Chart.yaml # Chart metadata
values.yaml # Default configuration values
charts/ # Dependency charts (subcharts)
templates/ # Kubernetes manifest templates
deployment.yaml
service.yaml
ingress.yaml
hpa.yaml
serviceaccount.yaml
_helpers.tpl # Reusable template partials
NOTES.txt # Post-install message template
tests/
test-connection.yaml
.helmignore # Files to exclude from packaging
The scaffolded chart follows Helm best practices: proper labeling, helper templates, and a sensible default deployment. It deploys an nginx container out of the box.
Every chart must contain a Chart.yaml. This file defines the chart’s identity and version information.
apiVersion: v2 # v2 for Helm 3 charts
name: myapp # Chart name (must match directory)
description: A Helm chart for my application
type: application # "application" or "library"
version: 0.1.0 # Chart version (SemVer)
appVersion: "1.0.0" # Version of the app being deployed
| Field | Required | Purpose |
|---|---|---|
apiVersion | Yes | Always v2 for Helm 3 |
name | Yes | Chart name, used in release naming |
version | Yes | Chart version — bump on every change |
appVersion | No | Version of the deployed application |
description | No | One-line summary shown in helm search |
type | No | application (default) or library |
version tracks the chart packaging. appVersion tracks the application inside it. They are independent — you can update the chart without changing the app, and vice versa.The values.yaml file provides default values that templates consume via {{ .Values.* }}. Users override these at install time.
# values.yaml
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "" # Defaults to chart appVersion
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: ""
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
# Inline override
helm install myrelease ./myapp --set replicaCount=3
# File override
helm install myrelease ./myapp -f production.yaml
Templates are Go-templated Kubernetes manifests. Helm renders them with values to produce valid YAML.
helm install.helm test validation.# templates/deployment.yaml (excerpt)
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
ports:
- containerPort: {{ .Values.service.port }}
Helm manages releases through four key commands. Each command tracks revisions so you can inspect history and roll back.
# 1. INSTALL — create a new release
helm install myrelease ./myapp --namespace default
# 2. UPGRADE — update an existing release
helm upgrade myrelease ./myapp --set image.tag=2.0.0
# 3. ROLLBACK — revert to a previous revision
helm rollback myrelease 1
# 4. UNINSTALL — remove the release entirely
helm uninstall myrelease
| Action | Revision | Status |
|---|---|---|
helm install | 1 | deployed |
helm upgrade | 2 | deployed |
helm rollback 1 | 3 | deployed (config from rev 1) |
Rollback creates a new revision — it does not delete history.
Helm provides several commands to query release state, history, and rendered manifests.
# List all releases in the current namespace
helm list
# Detailed status of a specific release
helm status myrelease
# Revision history with timestamps and descriptions
helm history myrelease
# Get the rendered manifests for the current revision
helm get manifest myrelease
# Get the computed values (defaults + overrides)
helm get values myrelease
NAME REVISION STATUS CHART APP VERSION
myrelease 2 deployed myapp-0.1.0 1.0.0
REVISION STATUS DESCRIPTION
1 superseded Install complete
2 deployed Upgrade complete
The NOTES.txt template renders post-install instructions. Users see this output after every helm install and helm upgrade.
# templates/NOTES.txt
1. Get the application URL by running:
{{- if .Values.ingress.enabled }}
http://{{ (index .Values.ingress.hosts 0).host }}
{{- else if eq .Values.service.type "NodePort" }}
export NODE_PORT=$(kubectl get svc {{ include "myapp.fullname" . }} -o jsonpath="{.spec.ports[0].nodePort}")
echo http://$NODE_IP:$NODE_PORT
{{- else if eq .Values.service.type "ClusterIP" }}
kubectl port-forward svc/{{ include "myapp.fullname" . }} 8080:{{ .Values.service.port }}
echo http://127.0.0.1:8080
{{- end }}
helm create and explore every filevalues.yaml for a real applicationNOTES.txt template