Helm Overview
Helm serves as the package manager for Kubernetes, analogous to apt or yum in Linux environments. It streamlines the deployment of applications within a Kubernetes cluster by enabling you to define, install, and upgrade complex applications through reusable packages called Charts.
Core Concepts
Chart
A Chart represents a self-contained package containing all necessary resources to run an application on Kubernetes. This includes Docker images, Kubernetes manifests, metadata, and service definitions. Charts function similarly to Homebrew formulas, APT packages (dpkg), or RPM files in traditional Linux package management.
Release
A Release denotes a specific instance of a Chart deployed to a Kubernetes cluster. The same Chart can be installed multiple times within a cluster, with each installation generating a distinct Release. For instance, if you need two separate MySQL databases, you would install the MySQL Chart twice, each creating its own Release with a unique name.
Repository
A Repository serves as a storage location where Charts are published and distributed from. You can configure multiple repositories and search across them to find available packages for installation.
Helm Architecture
Chart Installation Workflow
- Helm parses the Chart structure from a directory or compressed archive
- Helm transmits the Chart structure and Values to Tiller via gRPC
- Tiller constructs a Release based on the provided Chart and Values
- Tiller submits the Release to Kubernetes for execution
Chart Update Workflow
- Helm parses the Chart structure from a directory or compressed archive
- Helm sends the Release name, updated Chart structure, and Values to Tiller
- Tiller generates a new Release and updates the Release history for the specified name
- Tiller submits the updated Release to Kubernetes for execution
Installation
Helm consists of two primary components: the client CLI and the Tiller server component. Tiller runs as a pod within your Kubernetes cluster and handles the actual deployment operations.
If you're using Alibaba Cloud Container Service for Kubernetes, Tiller may already be pre-installed. In such cases, you only need to install the Helm client.
Download the appropriate release for your platform:
- Release page: https://github.com/helm/helm/releases
- Windows amd64: https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-windows-amd64.zip
- Linux arm64: https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-arm64.tar.gz
After downloading, extract the binary to a directory of your choice and add that directory to your system PATH.
Helm requires access to your Kubernetes cluster configuration. This can be achieved through the standard kubectl configuration (~/.kube/config) or by specifying a custom kubeconfig file with the --kubeconfig flag.
# Deploying an application named webapp using a Chart in ./chart directory
# with a custom kubeconfig file
/path/to/helm --kubeconfig /path/to/kube.conf install webapp ./chart
Server Installation
Initialize the Helm client and install Tiller in your cluster:
helm init
Chart repositories are optional since many teams bundle Charts alongside they source code in Git repositories. You can start a local repository server using
helm serveif needed.
Practical Usage
This section demonstrates Helm's capabilities by walking through the creation and deployment of a web application Chart. Docker image preparation is assumed to be completed beforehand.
Creating a Chart
Generate a new Chart using the helm create command:
helm create webapp
The generated structure includes:
webapp/
├── charts/ # Directory for dependency Charts
├── Chart.yaml # Chart metadata (name, version)
├── templates/ # Kubernetes manifest templates
│ ├── deployment.yaml
│ ├── _helpers.tpl # Shared template definitions (underscore prefix)
│ ├── ingress.yaml
│ ├── NOTES.txt # Installation instructions displayed post-deploy
│ └── service.yaml
└── values.yaml # Default parameter values for templates
Kubernetes Manifest Templates
deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: myregistry/webapp:2.1.0
ports:
- name: http
containerPort: 80
protocol: TCP
service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
selector:
app: webapp
ports:
- protocol: TCP
port: 80
targetPort: 80
ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: webapp-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: webapp-service
servicePort: 80
Converting to Template Files
Extracting parameters into template variables enables reuse across multiple environments. Templates use Go's text template syntax with double braces {{ }} for dynamic content injection.
deployment.yaml Template
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ .Release.Name }}
labels:
app: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: {{ .Release.Name }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
ports:
- name: http
containerPort: 80
protocol: TCP
service.yaml Template
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-service
spec:
selector:
app: {{ .Release.Name }}
ports:
- protocol: TCP
port: 80
targetPort: 80
ingress.yaml Template
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ .Release.Name }}-ingress
spec:
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
backend:
serviceName: {{ .Release.Name }}-service
servicePort: 80
values.yaml
ingress:
host: app.example.com
image:
repository: myregistry/webapp
tag: 2.1.0
replicas: 1
Installing and Upgrading Releases
Install a Chart:
helm install ./webapp
Install with custom parameters:
helm install \
--set replicas=2 \
--set ingress.host=staging.example.com \
./webapp
Upgrade an existing Release:
helm upgrade webapp ./webapp
Upgrade with custom parameters:
helm upgrade \
--set replicas=3 \
--set ingress.host=production.example.com \
webapp ./webapp
Atomic install-or-upgrade:
helm upgrade -i \
--set replicas=2 \
--set ingress.host=app.example.com \
webapp ./webapp
The -i (install) flag creates the Release if it doesn't exist, or updates it if it does.
Template Syntax Reference
Expressions
Template expressions are enclosed in double braces. Whitespace trimming variants:
{{ expression }}- standard output{{- expression }}- trim preceding whitespace{{ expression -}}- trim trailing whitespace{{- expression -}}- trim both
Variables and Scope
The dot (.) represents the root scope for accessing objects. Helm provides built-in global objects:
Values Object
Access values.yaml parameters:
{{ .Values.replicas }}
{{ .Values.image.repository }}
Release Object
| Property | Description |
|---|---|
| .Release.Name | Release identifier |
| .Release.Time | Installation timestamp |
| .Release.Namespace | Target namespace |
| .Release.Revision | Incrementing version number |
| .Release.IsUpgrade | True during upgrade operations |
| .Release.IsInstall | True during installation operations |
User-Defined Variables
Assign variables with :=:
{{- $releaseName := .Release.Name -}}
{{ $releaseName }}
Functions and Pipelines
Function Call:
{{ upper .Values.environment }}
Pipeline Operations:
{{ .Values.environment | upper }}
{{ .Values.environment | upper | quote }}
{{ .Values.environment | default "development" }}
{{ .Values.tag | repeat 3 }}
{{ .Values.description | nindent 2 }}
Comparison Operators
All operators function as template functions:
| Operator | Function | Description |
|---|---|---|
| == | eq |
Equal |
| != | ne |
Not equal |
| < | lt |
Less than |
| > | gt |
Greater than |
| && | and |
Logical AND |
| || | or |
Logical OR |
| ! | not |
Logical NOT |
{{ if and .Values.enabled (eq .Values.environment "production") }}
enabled: true
{{ end }}
Control Structures
Conditional Statements
{{ if eq .Values.drinks "coffee" }}
caffeinated: true
{{ else }}
caffeinated: false
{{ end }}
Scope Modification with with
The with statement changes the current scope:
{{- with .Values.configuration }}
maxConnections: {{ .max }}
timeout: {{ .timeout }}
{{- end }}
Access parent scope within with:
{{- $rootScope := . -}}
{{- with .Values.configuration }}
application: {{ $rootScope.Release.Name }}
maxConnections: {{ .max }}
{{- end }}
Looping with range
Iterating over maps:
{{- range $key, $value := .Values.configuration }}
{{ $key }}: {{ $value | quote }}
{{- end }}
Iterating over arrays:
{{- range .Values.servers }}
- {{ .name }}: {{ .address | quote }}
{{- end }}
Named Templates
Define reusable templates in files prefixed with underscore. These files (like _helpers.tpl) are not rendered directly to Kubernetes.
Definition:
{{- define "labels" -}}
app: {{ .Chart.Name }}
version: "{{ .Chart.Version }}"
{{- end -}}
Usage:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
labels:
{{ include "labels" . | nindent 4 }}
data:
config: "value"
Debugging Templates
Use --dry-run combined with --debug to preview rendered manifests without submitting them to Kubernetes:
helm upgrade \
--debug \
--dry-run \
-i \
--set replicas=2 \
--set ingress.host=app.example.com \
webapp ./webapp
This renders the templates with your provided values and displays the output, allowing you to verify correctness before actual deployment.