helm
Helm is the de facto package manager for Kubernetes. Often described as “the apt or yum of Kubernetes,” it turns a collection of Kubernetes resource definitions into a versioned, reusable package that can be installed, upgraded, and rolled back with a few commands.
Instead of maintaining loose YAML files for Deployments, Services, Ingresses, and other resources, teams can package them as a Chart, customize the deployment with Values, and manage each installation as a Release. This makes complex applications easier to distribute and operate consistently across environments.
Helm’s Core Concepts
Before using Helm, it helps to understand four key abstractions:
- Chart: The application package. It contains Kubernetes manifest templates, default configuration, and metadata.
- Repository: A source of downloadable Charts, similar to a package repository for Linux software.
- Release: A running instance of a Chart in a Kubernetes cluster. The same Chart can be installed multiple times under different release names.
- Values: Configuration data supplied during installation or upgrade. Templates use these values to generate environment-specific manifests.
This model separates reusable application logic from deployment-specific configuration. A Chart describes how an application should run, while Values determine the details of a particular deployment.
Installing Helm
Helm 3 requires no server-side component such as Tiller. The client communicates directly with the Kubernetes API, so installation is straightforward.
On macOS with Homebrew:
brew install helm
On Linux, Helm provides an installation script:
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Verify the installation:
helm version
For production systems, teams may prefer to download a specific release, verify its checksum, and install it through an internal tooling pipeline rather than executing a remote script directly.
Deploying Your First Application
The following example installs an Nginx chart from the Bitnami repository:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
Search the repository for available charts:
helm search repo nginx
Install a release named my-nginx:
helm install my-nginx bitnami/nginx
Helm renders the Chart’s templates, creates the Kubernetes resources, and records the result as a Release. The command output usually includes instructions for interacting with the application, such as a command for port forwarding.
List active releases with:
helm list
Repository indexes are refreshed manually, so running helm repo update before a search or installation helps ensure that the latest Chart versions are available.
Configuring a Release
Every Chart exposes a set of default values. To inspect them before installation, run:
helm show values bitnami/nginx
Values can be overridden in several ways. A local YAML file is usually the clearest option:
replicaCount: 3
service:
type: NodePort
image:
tag: "1.27.1"
Pass that file during installation:
helm install my-nginx bitnami/nginx -f my-values.yaml
For quick changes, individual values can also be set on the command line:
helm install my-nginx bitnami/nginx \
--set replicaCount=3 \
--set service.type=NodePort
A Values file is generally preferable for important or environment-specific settings. Command-line overrides are convenient for testing, but long and nested --set expressions can become difficult to read and maintain.
Upgrading and Rolling Back
Helm records each successful upgrade as a new release revision. To change the replica count of an existing release:
helm upgrade my-nginx bitnami/nginx --set replicaCount=5
Review the release history:
helm history my-nginx
If the new revision causes a problem, return to an earlier one:
helm rollback my-nginx 1
You can also wait for resources to become ready and automatically undo a failed upgrade:
helm upgrade my-nginx bitnami/nginx \
--set replicaCount=5 \
--atomic \
--wait
A rollback restores the manifests and configuration recorded in the selected revision, but it cannot reverse every side effect. Database migrations, external messages, or changes made outside Kubernetes may still require separate handling.
Anatomy of a Chart
The following command creates a starter Chart:
helm create mychart
A typical Chart directory looks like this:
mychart/
├── .helmignore
├── Chart.yaml
├── values.yaml
├── values.schema.json
├── charts/
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ └── NOTES.txt
└── templates/
└── tests/
└── test-connection.yaml
The most important files are:
Chart.yaml: Contains metadata such as the Chart name, version, description, and application version.values.yaml: Defines default configuration values.templates/: Contains Kubernetes manifests written with Go template syntax.charts/: Stores dependency Charts.values.schema.json: Optionally validates the structure and types of supplied values.
A minimal Chart.yaml might contain:
apiVersion: v2
name: mychart
description: A reusable application chart
type: application
version: 0.1.0
appVersion: "1.27.0"
The Chart version identifies the package itself, while appVersion identifies the application version being packaged.
Writing Templates
Helm templates combine Kubernetes resources with values from the release environment. For example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web
labels:
app: web
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 80
Templates can access several important objects:
.Valuescontains configuration supplied by the user..Releaseincludes the release name, namespace, revision, and service type..Chartcontains metadata fromChart.yaml..Capabilitiesdescribes the Kubernetes cluster’s supported features..Templateprovides information about the template currently being rendered.
Helper functions in _helpers.tpl reduce duplication and produce consistent resource names and labels. For example:
{{- define "mychart.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
The result can then be reused throughout the Chart:
metadata:
name: {{ include "mychart.fullname" . }}
Render the templates locally without contacting a cluster:
helm template my-nginx ./mychart
This is useful for reviewing generated manifests, validating templates, or integrating Helm into CI/CD workflows.
Essential Commands
| Command | Purpose |
|---|---|
helm install |
Install a Chart as a new Release |
helm upgrade |
Upgrade an existing Release |
helm rollback |
Restore a previous release revision |
helm history |
Display revision history |
helm uninstall |
Remove a Release and its managed resources |
helm template |
Render templates locally without installing them |
helm lint |
Check a Chart for syntax and convention issues |
helm package |
Package a Chart into a .tgz archive |
helm repo |
Add, update, list, and index repositories |
helm show |
Display Chart metadata, values, or documentation |
To remove a release:
helm uninstall my-nginx
To validate a Chart before packaging it:
helm lint ./mychart
helm package ./mychart
Production Best Practices
Keep Configuration Separate from Templates
Templates should remain reusable, while environment-specific differences belong in Values files. Store production, staging, and development configurations under version control:
environments/
├── production-values.yaml
├── staging-values.yaml
└── development-values.yaml
Preview Every Change
Use helm template to inspect the rendered output before deployment. The helm diff plugin can also show what an upgrade would change. These checks catch accidental resource removals, malformed manifests, and unexpected configuration changes.
Pin Versions
Avoid relying on an unpinned “latest” Chart or image tag. A repeatable deployment should specify the exact Chart version and, where practical, a container image digest:
helm install my-nginx bitnami/nginx --version 1.2.3
This reduces the chance that the same release produces different resources at different times.
Validate in CI
A CI pipeline can run linting and rendering tests on every change:
helm lint ./mychart
helm template test-release ./mychart > rendered.yaml
Additional checks can verify generated resource names, required labels, security contexts, and environment-specific settings.
Protect Sensitive Values
Do not commit passwords, API tokens, or private keys to Values files. Use an external secret manager, a secrets plugin, or an encrypted delivery mechanism, and restrict access to sensitive Kubernetes Secrets.
Use Semantic Versioning
Treat Chart versions as part of your API contract. Increment the major version when a breaking change is introduced, the minor version for backward-compatible features, and the patch version for fixes.
Test Failure Paths
Use --dry-run, --debug, --wait, and --atomic to validate release behavior. Test upgrades and rollbacks in a realistic cluster, especially when a Chart manages persistent data or irreversible operations.
Why Helm Matters
Helm adds three important capabilities to Kubernetes application management: packaging, configuration injection, and release history. Together, they replace ad hoc manifest handling with a repeatable and auditable deployment workflow.
Whether deploying a database, a monitoring stack, or an internal service, Helm gives teams a shared way to package, configure, inspect, and evolve applications. The quickest way to begin is to install a community Chart, modify its Values, and then use helm create to build a small Chart of your own.