Helm - Package manager

Table of contents
- Introduction to Helm
- π Helm 2 vs Helm 3 β Key Differences
- β Summary
- π§ Helm Components
- π Helm Charts β Chart.yaml File Explained
- π Helm CLI β Core Commands & Usage
- π Artifact Hub (artifacthub.io)
- π Searching for Charts
- π₯ Adding and Using Helm Repositories
- π Installing and Managing Releases
- βοΈ Customizing Helm Chart Parameters
- β Summary
- π οΈ Helm Lifecycle Management
- Helm Charts Anatomy
- π§ Helm Charts Overview
- π οΈ Creating a Helm Chart from Scratch
- β οΈ Problem with Static Values
- π§© Helm Templating β Solving the Static Values Problem
- β Solution: Templatize the Chart
- π§ Helm Built-in Objects
- π οΈ Example Templatization in YAML Files
- ποΈ values.yaml Example
- π‘ Key Notes
- π§ͺ Final Test
- β Making Sure a Helm Chart Works as Intended
- π¦ Helm Template Functions & Deployment Notes
- π Helm Pipelines & String Functions
- π οΈ Helm Conditionals and values.yaml Explained
- π Helm range β Looping Over Lists
- π§Ύ Named Templates in Helm
- π§© Helm Chart Hooks
- π§Ύ Question
- β Solution
- π¦ Helm Chart Packaging, Signing, and Verification
- π¦ Uploading Helm Charts and Using a Custom Chart Repository

Introduction to Helm
Helm is a package manager for Kubernetes that simplifies deploying, managing, and upgrading applications using reusable templates called charts. It lets you define infrastructure as code, customize deployments with values, and easily roll back or upgrade versionsβmaking Kubernetes app management faster, repeatable, and more consistent.
π Helm 2 vs Helm 3 β Key Differences
Feature | Helm 2 | Helm 3 |
Tiller | β Used a server-side component called Tiller to manage releases in the cluster. This added complexity and raised security concerns (e.g., cluster-wide access). | β Tiller removed. Helm 3 runs client-side, using the user's kubeconfig for direct accessβsimpler and more secure. |
Security | Required complex RBAC configuration to secure Tiller. | More secure by designβHelm respects Kubernetes native access control. |
Release Management | Releases tracked by Tiller, could list all cluster-wide. | Releases are now namespaced, aligning with Kubernetes best practices. |
Upgrade Strategy | Used a two-way merge, often overwriting changes made manually on the cluster. | Uses a three-way strategic merge patch, which compares the live state, previous release, and new configβminimizes conflicts and preserves manual changes. |
Revisions | Commands like helm upgrade created new revisions, but rollback behavior could be unpredictable. | Revisions are managed more cleanly:β’ helm install wordpress β Revision 1β’ helm upgrade wordpress β Revision 2β’ helm rollback wordpress β Revision 3 (but content is same as Revision 1) |
CRDs (Custom Resource Definitions) | Managed like normal resources, often causing issues during upgrades. | Supports a dedicated crds/ directory for safer, idempotent CRD installation. |
OCI Support | β Not available. | β Helm 3 supports storing and retrieving charts from OCI-compliant registries (like Docker Hub). |
β Summary
Helm 3 addresses the architectural and security limitations of Helm 2 by removing Tiller, implementing a three-way strategic merge for safer upgrades, and aligning more closely with Kubernetes best practices. Itβs the current and recommended version for production use.
π§ Helm Components
1. Helm Command Line Utility (CLI)
Helm is operated through a command-line tool installed on the local system. This utility is used to execute various Helm actions such as installing a chart, upgrading an existing application, rolling back to a previous version, and managing deployments in a Kubernetes cluster. It interacts directly with the Kubernetes API and plays a crucial role in managing the lifecycle of applications deployed using Helm charts.
2. Charts
Helm uses charts to package applications. A chart is a structured collection of files that contains all the necessary instructions and definitions (in YAML format) for deploying a group of Kubernetes resources. These may include deployments, services, ConfigMaps, secrets, and more. Charts simplify application deployment by encapsulating complex configurations into reusable, versioned packages.
Helm charts are typically available from public repositories like ArtifactHub.io, which hosts thousands of charts maintained by the community (e.g., Bitnami, TrueCharts, Appscode, Community Operators). Users can download and use these charts without having to build them from scratch.
3. Templates and the values.yaml
File
Inside a Helm chart, the core of customization lies in the templating mechanism. Rather than hardcoding values such as image names, replica counts, or environment variables into the deployment YAML, Helm uses Go-based templates. These templates dynamically pull their values from a file called values.yaml
.
For example, in a basic Nginx-based web server application that includes a deployment and a service, the image name and number of replicas are not directly written in the deployment file. Instead, they are templated and sourced from values.yaml
.
The values.yaml
file serves as the configuration input for the chart. It contains the default values for all configurable parameters of the application. In most real-world cases, this is the only file that users need to edit in order to customize their application deployment. It acts as the "settings file" that makes Helm charts reusable and easily configurable.
4. Releases and Revisions
When a Helm chart is installed into a Kubernetes cluster (e.g., helm install my-site bitnami/wordpress
), a release is created. A release is a named, running instance of a Helm chart deployed in a specific namespace of the Kubernetes cluster. You can deploy multiple releases of the same chart by giving each one a unique name. This flexibility allows teams to run several environments (e.g., dev, staging, prod) using the same chart.
Every time a release is upgraded or rolled back, Helm creates a new revision. These revisions are like snapshots that track the state of the application at a certain point in time:
helm install wordpress
creates revision 1helm upgrade wordpress
creates revision 2helm rollback wordpress
creates revision 3, but it reverts to the state from revision 1
Helm 3 improves this process using a three-way strategic merge patch, which compares the live state, the old manifest, and the new manifest. This allows for safer upgrades by preserving manual changes made to the cluster.
5. Metadata Management
To track what charts have been installed, what configurations were used, and what revision state each release is in, Helm stores metadata β essentially, data about the deployments. This metadata is stored directly inside the Kubernetes cluster using Kubernetes Secrets. These Secrets are accessible by users who have access to the cluster and ensure that deployment history is preserved for as long as the cluster exists. This design allows for better visibility and auditing of deployments within the project.
6. Why Use Helm Charts from Public Repos?
Most of the time, users do not need to write Helm charts from scratch because well-tested and customizable charts already exist in public repositories like:
Bitnami
TrueCharts
Appscode
Community Operators
Available collectively on ArtifactHub.io
These charts are designed with flexibility in mind and expose a rich set of parameters via values.yaml
, enabling users to tailor the deployment to their specific requirements without altering the chart templates directly.
π Helm Charts β Chart.yaml
File Explained
In every Helm chart, aside from the values.yaml
file used for configuration, there is a mandatory file named Chart.yaml
. This file contains metadata about the chart itself and plays a crucial role in chart identification, versioning, and dependency management.
π Purpose of Chart.yaml
The Chart.yaml
file provides essential metadata for a Helm chart. Helm uses this file to understand what the chart is, how it relates to applications, and how it should be processed during packaging, installation, or upgrade.
π§© Key Fields in Chart.yaml
Field | Description |
apiVersion | Specifies the version of the chart API being used. |
- v1 : for Helm 2 | |
- v2 : for Helm 3 | |
name | The name of the chart. This is the unique identifier for the chart within a repository. |
version | The version of the chart itself, separate from the application version. It is used for tracking updates to the chart. |
appVersion | The version of the actual application being deployed by this chart. |
description | A short summary describing what this chart does or which application it deploys. |
type | Indicates the type of chart: |
β application (default): Charts that deploy applications. | |
β library : Charts that provide helper templates and functions, used by other charts. | |
keywords | A list of relevant keywords associated with the chart. Useful for search and discovery in chart repositories. |
home (optional) | A URL to the homepage of the project or application. |
icon (optional) | A URL to an icon image representing the application. Helpful in GUI-based Helm dashboards. |
maintainers | A list of individuals or teams responsible for maintaining the chart. Includes their names and optionally email/contact info. |
dependencies | Lists other charts that this chart depends on. For example, a WordPress chart may declare a dependency on a MariaDB chart. This allows Helm to handle both installations together without manually merging manifest files. |
π¦ Example Use Case: WordPress with MariaDB
In a Helm chart for deploying WordPress:
Instead of manually combining WordPress and MariaDB YAML manifests, you can declare MariaDB as a dependency in
Chart.yaml
.This way, Helm will automatically fetch and deploy MariaDB alongside WordPress when the chart is installed.
Helm chart structure
π Helm CLI β Core Commands & Usage
Helm simplifies application deployment on Kubernetes by offering powerful command-line utilities. Here's a breakdown of essential Helm commands and concepts for working with repositories and deploying charts.
π§° Basic Helm CLI Help
helm --help
:
Displays general help about Helm commands, structure, and usage.helm repo --help
:
Provides help related to Helm repository management commands like adding, listing, and updating chart repos.helm repo update --help
:
Shows information about how to update your local list of chart repositories (similar toapt-get update
for package managers).
π Artifact Hub (artifacthub.io
)
Artifact Hub is a public platform to browse and discover Helm charts created by the community and vendors.
It contains charts from well-known publishers like Bitnami, TrueCharts, Appscode, and many others.
You can search, review, and get installation instructions for charts directly from the site.
From the Artifact Hub, you can copy Helm commands to install a chart directly into your cluster.
π Searching for Charts
Helm allows you to search for charts using the CLI:
Search in Artifact Hub via CLI:
helm search hub wordpress
Searches charts in Artifact Hub (not just what's on your local machine).
Requires internet access and Helm 3.1+.
Search in Added Repositories:
helm search repo wordpress
- Searches only within your locally added Helm repositories.
π₯ Adding and Using Helm Repositories
Before installing a chart, you often need to add the repo that contains it:
Add a Helm chart repository (e.g., Bitnami):
helm repo add bitnami https://charts.bitnami.com/bitnami
Update your local repo index:
helm repo update
This downloads the latest chart information, just like
sudo apt-get update
.List all added repos:
helm repo list
π Installing and Managing Releases
Install a chart (e.g., WordPress from Bitnami):
helm install my-release bitnami/wordpress
This installs the chart as a release named
my-release
.Helm will deploy all necessary Kubernetes objects (e.g., Deployments, Services, PVCs).
List all deployed releases:
helm list
Uninstall a release:
helm uninstall my-release
- This removes the deployed application and all its associated Kubernetes resources.
β Summary
Deploying an application on a Kubernetes cluster has never been easier than with Helm.
Helm streamlines:
Finding and managing charts
Installing and configuring applications
Updating and rolling back deployments
With repositories like Bitnami and tools like Artifact Hub, Helm provides a robust ecosystem for production-grade application management on Kubernetes.
βοΈ Customizing Helm Chart Parameters
By default, Helm installs applications using values from the chartβs built-in values.yaml
file. However, you often need to override or customize these values to tailor the deployment to your environment.
Helm provides three main ways to customize chart parameters:
π§ 1. Override Parameters via Command Line (--set
)
You can directly override values from the default values.yaml
using the --set
flag during installation.
Example:
helm install --set wordpressBlogName="Helm Tutorials" my-release bitnami/wordpress
This overrides the
wordpressBlogName
field.Itβs quick and easy for simple one-off changes.
For multiple values, use:
helm install --set key1=value1,key2=value2 my-release bitnami/wordpress
π 2. Use a Custom values.yaml
File (--values
)
For more complex or structured configurations, it's better to create a custom YAML file with all your overrides and pass it during installation.
Example:
helm install --values custom-values.yaml my-release bitnami/wordpress
Keeps your custom settings separate.
Easier to version-control and reuse.
Highly recommended for team-based or production deployments.
π οΈ 3. Modify the Original Chart Files
If you want full control, including editing templates or default values.yaml
, you can pull and extract the chart locally.
Steps:
helm pull bitnami/wordpress
helm pull --untar bitnami/wordpress
This creates a local
wordpress/
directory with the full chart source.You can now:
Edit the
values.yaml
file directly.Modify templates inside the
templates/
folder.
Then install from the local chart:
helm install my-release ./wordpress
Use this method when:
You need to deeply customize logic or structure.
You want to build your own version of a chart.
β Summary
Method | Description | Best For |
--set | Override specific values inline | Quick changes |
--values custom.yaml | Use a separate config file | Reusability, cleaner setup |
Modify pulled chart | Full customization of values and templates | Advanced use, custom charts |
β οΈ Always review the chartβs default
values.yaml
(viahelm show values bitnami/wordpress
) to know what options are available for customization.
π οΈ Helm Lifecycle Management
π¦ What is a Helm Release?
A release is a deployed instance of a chart.
It represents a package of Kubernetes objects.
Helm tracks all resources belonging to a release, so it can:
Upgrade
Rollback
Uninstall
without affecting other releases.
π Helm Install Examples:
helm install my-site bitnami/wordpress
helm install my-second-site bitnami/wordpress
- Each command creates a separate release even if from the same chart.
π§© Installing Specific Versions:
helm install nginx-release bitnami/nginx --version 7.1.0
- Deploys a specific chart version.
π Upgrading a Release:
helm upgrade nginx-release bitnami/nginx
Creates a new revision (v2).
Helm tracks the revision history.
π View Lifecycle Details:
helm list # List all releases
helm history nginx-release # Show revisions with metadata
kubectl get pods # Get pod names
kubectl describe pod <pod-name> # View image info
βͺ Rollback:
helm rollback nginx-release 1
Restores configuration from revision 1.
Creates a new revision, not literally going back.
Note: App data (e.g., DB contents) is not restored.
β οΈ Upgrade Issues:
If upgrade fails due to permission errors (e.g., DB credentials):
Use Helm CLI flags as recommended in error messages.
Helm may need access to admin credentials (DB, WordPress).
π§ Important Notes:
Helm manages manifests/declarations, not runtime data.
Rollbacks restore config/state, not data volumes or files created by the app.
Helm Charts Anatomy
π§ Helm Charts Overview
Helm charts are incredibly versatile and can automate almost any kind of Kubernetes package installation that we can think of. Although charts are technically not programs, they can act like programs.
Besides just installing various Kubernetes objects to get our app up and running, they can do some extra stuff too. For example, we can write the chart in such a way that whenever we do a Helm upgrade, a database can be automatically backed up before that happens. So we have a way to restore data from backup in case something goes wrong.
π οΈ Creating a Helm Chart from Scratch
Suppose we have a helloworld
Deployment and Service YAML file.
1. Create a Helm Chart:
$ helm create nginx-chart
2. Edit Chart Metadata:
$ cd nginx-chart
$ vi Chart.yaml
Sample Chart.yaml:
apiVersion: v2
name: nginx-chart
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
maintainers:
- email: john@example.com
name: john smith
3. Remove Sample Templates:
$ rm -r templates/*
4. Add Your Own YAML Files:
Place your existing deployment.yaml
and service.yaml
into the templates/
directory.
Structure:
nginx-chart/
βββ Chart.yaml
βββ values.yaml
βββ templates/
βββ deployment.yaml
βββ service.yaml
5. Example Service and Deployment Files:
service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
type: NodePort
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: hello-world
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 2
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: nginx
ports:
- name: http
containerPort: 80
protocol: TCP
β οΈ Problem with Static Values
These files contain static values:
Name of deployment (
hello-world
)Number of replicas
Container name
Scenario:
$ helm install hello-world-1 ./nginx-chart
Then:
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 0/2 2 0 24s
Trying another install with different release name:
$ helm install hello-world-2 ./nginx-chart
β Error:
Deployment "hello-world" in namespace "default" exists and cannot be imported into the current release:
invalid ownership metadata; annotation validation error:
key "meta.helm.sh/release-name" must equal "hello-world-2": current value is "hello-world-1"
Root cause: The name hello-world
is hardcoded in the YAML files and causes a conflict when deploying multiple releases.
π§© Helm Templating β Solving the Static Values Problem
β οΈ Problem Recap
Static values like deployment names (
hello-world
) in the YAML files cause errors when installing the same chart with different release names:$ helm install hello-world-1 ./nginx-chart $ helm install hello-world-2 ./nginx-chart Error: rendered manifests contain a resource that already exists.
β Solution: Templatize the Chart
π― Purpose of Templating
Templating allows dynamic rendering of values based on:
Release information (name, namespace, etc.)
Chart metadata
User-defined values from
values.yaml
Cluster capabilities
π§ Helm Built-in Objects
π§· .Release
.Release.Name
β Name of the release (e.g.,hello-world-1
).Release.Namespace
.Release.IsInstall
.Release.IsUpgrade
.Release.Revision
.Release.Service
π¦ .Chart
.Chart.Name
.Chart.ApiVersion
.Chart.Version
.Chart.Type
.Chart.Keywords
.Chart.Home
π .Capabilities
.Capabilities.KubeVersion
.Capabilities.ApiVersions
.Capabilities.HelmVersion
.Capabilities.GitCommit
.Capabilities.GitTreeState
.Capabilities.GoVersion
βοΈ .Values
User-defined values from
values.yaml
Example:
replicaCount: 2 image: repository: nginx pullPolicy: IfNotPresent tag: "1.16.0"
π οΈ Example Templatization in YAML Files
β
Deployment Template (templates/deployment.yaml
)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}-nginx
template:
metadata:
labels:
app: {{ .Release.Name }}-nginx
spec:
containers:
- name: {{ .Release.Name }}-nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
β
Service Template (templates/service.yaml
)
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-svc
spec:
type: NodePort
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: {{ .Release.Name }}-nginx
ποΈ values.yaml
Example
# Default values for nginx-chart.
replicaCount: 2
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.16.0"
π‘ Key Notes
.Release
,.Chart
, and.Capabilities
follow CapitalCase because they are built-in..Values
follow lower-case (or user-defined) because they are user-defined.When we install a Helm chart, Helm merges:
Templates
Release-specific info
Chart metadata
Values.yaml
β to render final Kubernetes manifest files.
π§ͺ Final Test
$ helm install hello-world-1 ./nginx-chart
$ helm install hello-world-2 ./nginx-chart
$ kubectl get deployment
Result:
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world-1-nginx 1/2 2 1 8s
hello-world-2-nginx 0/2 2 0 4s
Now, both releases work independently without conflict.
β Making Sure a Helm Chart Works as Intended
Before installing a Helm chart into your Kubernetes cluster, it's crucial to verify its correctness using 3 main techniques:
π 1. Linting the Chart
Purpose: Detect syntax or structural issues in the chart and YAML files.
Command:
helm lint ./nginx-chart
What it does:
Validates the chart structure.
Detects template syntax errors (like wrong object references).
Flags YAML formatting issues.
Example Error Output:
[ERROR] templates/: template: nginx-chart/templates/deployment.yaml:4:19: executing "nginx-chart/templates/deployment.yaml" at <.Releese.Name>: nil pointer evaluating interface {}.Name
(Note the typo
.
Releese.Name
β should be.
Release.Name
)
π§ͺ 2. Template Rendering
Purpose: Renders chart templates locally and lets you see the final manifest output.
Command:
helm template ./nginx-chart
With debug for more detail:
helm template ./nginx-chart --debug
Use Case: Helpful for catching logic or formatting issues, like indentation or template logic problems.
Example Debug Output:
Error: YAML parse error on nginx-chart/templates/deployment.yaml: error converting YAML to JSON: yaml: line 5: mapping values are not allowed in this context
Important: This will not catch Kubernetes-specific semantic errors (e.g., using
container
instead ofcontainers
).
π§ͺ 3. Dry Run Installation
Purpose: Simulates a full install to ensure Kubernetes would accept the manifests.
Command:
helm install hello-world-1 ./nginx-chart --dry-run
What it does:
Runs full rendering and validation as if installing to the cluster.
Checks for errors that would occur at runtime in Kubernetes.
Best for:
Catching things like typos in Kubernetes manifest fields (
container
vscontainers
).Verifying that all resources would deploy correctly.
π Summary of Template Values Used
Object Type | Example Key | Example Value |
. Release.Name | {{ . Release.Name }} | hello-world-1 |
.Values.replicaCount | {{ .Values.replicaCount }} | 2 |
.Values.image.repository | {{ .Values.image.repository }} | nginx |
π File Example Snippets
values.yaml
:
replicaCount: 2
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.16.0"
deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
ports:
- name: http
containerPort: 80
protocol: TCP
service.yaml
:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-svc
spec:
type: NodePort
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: hello-world
By using lint
, template
, and --dry-run
in combination, you can be confident that your Helm charts are well-formed, valid, and ready for Kubernetes deployment.
π¦ Helm Template Functions & Deployment Notes
π οΈ Helm Template Usage in deployment.yaml
Helm uses Go templating to inject dynamic values into Kubernetes manifests. Examples:
metadata:
name: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
containers:
- name: hello-world
image: {{ .Values.image.repository }}
π Helm Chart Files Breakdown
β
values.yaml
β Default Configurations
replicaCount: 2
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.16.0"
β
templates/deployment.yaml
β Templatized Manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: {{ .Values.image.repository }}
ports:
- name: http
containerPort: 80
protocol: TCP
π Helm Templating: String Functions
Helm provides powerful built-in functions for string manipulation:
Function | Example | Output |
upper | {{ upper .Values.image.repository }} | "NGINX" |
quote | {{ quote .Values.image.repository }} | "nginx" |
replace "x" "y" | {{ replace "x" "y" .Values.image.repository }} | "nginy" |
shuffle | {{ shuffle .Values.image.repository }} | e.g. "xignn" |
π Full List:
Helm Template Function List β String Functions
Other categories:
Cryptographic & Security
File Path
Lists
Dictionaries
Kubernetes
Logic, Math, Regex, Encoding, URL, Type Conversion, etc.
β οΈ Common Pitfall: InvalidImageName
When running:
kubectl get pods
You may see:
NAME READY STATUS RESTARTS AGE
nginx-deployment-xxxx 0/1 InvalidImageName 0 3s
This happens if the image path is incorrect or misconfigured. Helm templates wonβt catch this β only Kubernetes will.
β
Always verify .Values.image.repository
resolves to a valid image string like nginx:1.16.0
.
π§ Using Default Values
If a value isn't passed, use default
:
image: {{ default "nginx" .Values.image.repository }}
π Helm Pipelines & String Functions
π§ͺ Pipelines in Helm
Just like in Linux:
$ echo "abcd"
abcd
$ echo "abcd" | tr a-z A-Z
ABCD
Helm templates also allow pipelining β chaining multiple functions together:
π Helm String Functions (Examples)
1οΈβ£ Convert to UPPERCASE
{{ upper .Values.image.repository }}
If the value is:
image:
repository: nginx
It becomes:
NGINX
2οΈβ£ Using |
(pipe) for cleaner syntax
{{ .Values.image.repository | upper }}
Output:
NGINX
3οΈβ£ Add quotes using quote
{{ .Values.image.repository | upper | quote }}
Output:
image: "NGINX"
4οΈβ£ Add shuffle
for random character order (demo)
{{ .Values.image.repository | upper | quote | shuffle }}
Output (varies randomly):
image: "GNXNI"
(Helm will output a random arrangement of "NGINX"
each time)
π οΈ Helm Conditionals and values.yaml
Explained
π What is values.yaml
?
The
values.yaml
file defines default configuration values used in Helm templates.These values are referenced in Helm templates using the
{{ .Values.<key> }}
syntax.
Example:
# values.yaml
replicaCount: 2
image: nginx
orgLabel: payroll
serviceAccount:
create: true
π Example Helm Template (service.yaml):
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-nginx
{{- if .Values.orgLabel }}
labels:
org: {{ .Values.orgLabel }}
{{- end }}
spec:
ports:
- port: 80
name: http
selector:
app: hello-world
β Conditional Logic in Helm
Helm templates support Go templating with conditional logic like:
{{- if .Values.orgLabel }}
labels:
org: {{ .Values.orgLabel }}
{{- else if eq .Values.orgLabel "hr" }}
labels:
org: human resources
{{- else }}
labels:
org: default
{{- end }}
π£ Functions in Helm Conditionals
Function | Purpose |
eq | Equals |
ne | Not equal |
lt | Less than |
le | Less than or equal |
gt | Greater than |
ge | Greater than or equal |
not | Negation |
empty | Checks if a value is empty |
π§ͺ Example: serviceaccount.yaml
Conditional Creation
# values.yaml
serviceAccount:
create: true
# serviceaccount.yaml
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Name }}-robot-sa
{{- end }}
π§ Helm Templating: Using with
for Scope Control
In Helm templates, {{ with ... }}
is used to narrow the scope to a specific section of values, reducing redundancy and improving readability. When you use with
, the context (.
) inside the block becomes the specified object.
ποΈ Example: values.yaml Structure
app:
ui:
bg: red
fg: black
db:
name: "users"
conn: "mongodb://localhost:27020/mydb"
π Without with
: Full Path Required
data:
background: {{ .Values.app.ui.bg }}
foreground: {{ .Values.app.ui.fg }}
database: {{ .Values.app.db.name }}
connection: {{ .Values.app.db.conn }}
β
With with
: Cleaner & Scoped
{{- with .Values.app }}
{{- with .ui }}
background: {{ .bg }}
foreground: {{ .fg }}
{{- end }}
{{- with .db }}
database: {{ .name }}
connection: {{ .conn }}
{{- end }}
{{- end }}
Here, .bg
, .fg
, .name
, and .conn
are used instead of the full path, because scope is now limited to app
, ui
, and db
respectively.
𧨠Common Error
Error: template: ... at <.Release.Name>: nil pointer evaluating interface {}.Name
Cause: You are outside the original root scope (.
) when accessing .
Release.Name
.
Fix: Use $
to refer to the root context:
release: {{ $.Release.Name }}
π Helm range
β Looping Over Lists
π Example values.yaml
regions:
- ohio
- newyork
- ontario
- london
- singapore
- mumbai
π Example configmap.yaml
Template
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-regioninfo
data:
regions:
{{- range .Values.regions }}
- {{ . | quote }}
{{- end }}
π§ Whatβs Happening:
range .Values.regions
loops through each value in theregions
list..
inside the loop refers to the current region (e.g.,"ohio"
).quote
adds double quotes around each region name.{{-
and-}}
remove whitespace for cleaner YAML.
β Rendered Output
If .
Release.Name
= demo
, then:
Version: v1
kind: ConfigMap
metadata:
name: demo-regioninfo
data:
regions:
- "ohio"
- "newyork"
- "ontario"
- "london"
- "singapore"
- "mumbai"
π§Ύ Named Templates in Helm
Named templates in Helm are reusable blocks that help avoid duplication in Kubernetes manifest files. These templates are commonly stored in _helpers.tpl
.
π¦ Define a Template in _helpers.tpl
{{- define "labels" }}
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: nginx
{{- end }}
This defines a template block called "labels"
.
π service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-nginx
labels:
{{- template "labels" . }}
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: hello-world
β
include
is used with | indent 4
to correctly align the template output under labels
.
π deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
labels:
{{- template "labels" . }}
spec:
selector:
matchLabels:
{{- include "labels" . | indent 2 }}
template:
metadata:
labels:
{{- include "labels" . | indent 4 }}
spec:
containers:
- name: nginx
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
template
is used when no piping or indentation is needed.include
is used when output needs to be indented to fit YAML structure.
π Why Use .
(Dot Operator)?
The
.
(dot) passes the current context (e.g.,.
Release.Name
) to the named template.Without
.
, the template cannot access Helm values like.Values
,.Chart
, or.Release
.
β Correct:
{{ include "labels" . }}
{{ template "labels" . }}
β Incorrect:
{{ include "labels" }}
π§© Helm Chart Hooks
Helm hooks allow us to inject custom lifecycle events during chart operations (install
, upgrade
, delete
, rollback
), enabling advanced actions like:
Backing up a database before an upgrade
Displaying a site-wide announcement during upgrades
Sending email alerts during install or delete
π οΈ Example Use Case: Backup Database Before Upgrade
Imagine you have a script called backup.sh
that backs up your database. You want Kubernetes to execute this once before each upgrade.
To run it only once (instead of continuously like a Pod), use a Kubernetes Job, and configure it with a Helm hook.
βοΈ Helm Lifecycle and Hook Events
Typical lifecycle during a helm upgrade
:
helm upgrade β verify β render β upgrade
With hooks, you can insert steps like:
pre-install
post-install
pre-upgrade
post-upgrade
pre-delete
post-delete
pre-rollback
post-rollback
π§ Hook Configuration Example (backup-job.yaml
)
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-pre-upgrade-backup
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
name: backup-database
spec:
restartPolicy: Never
containers:
- name: pre-upgrade-backup-job
image: alpine
command: ["/bin/sh", "-c", "/bin/backup.sh"]
helm.sh/hook
: tells Helm when to run the hook (pre-upgrade
).helm.sh/hook-weight
: controls execution order if multiple hooks are defined.helm.sh/hook-delete-policy
: cleans up after execution (e.g.,hook-succeeded
).
π File Placement
Place backup-job.yaml
inside your chartβs templates/
directory (like any other template file). Even though it's there, Helm wonβt treat it like a regular deployment due to the hook
annotation.
π How Multiple Hooks Are Ordered
If multiple hooks exist for the same event (pre-upgrade
, for instance):
They are sorted by
hook-weight
(lowest first).If weights are the same:
Sorted by resource kind (alphabetical)
Then by resource name
This allows precise control over the execution order, which is critical when different jobs depend on one another.
π§Ή Hook Resource Cleanup
Without cleanup, Kubernetes will keep the Job in the cluster after it runs. To avoid clutter or name collisions:
Use:
"helm.sh/hook-delete-policy": hook-succeeded
Other valid values:
hook-failed
before-hook-creation
This ensures each hook resource is removed after it completes (or before the next run).
β Summary
Feature | Purpose |
helm.sh/hook | Defines when the hook runs |
helm.sh/hook-weight | Controls execution order |
helm.sh/hook-delete-policy | Deletes hook resources after execution |
Job (vs Pod) | One-time script execution |
π¦ Typical Workflow Example
$ helm upgrade myapp ./mychart
β Helm sees a pre-upgrade hook in backup-job.yaml
β Runs the backup.sh script inside a Job
β Waits for it to succeed
β Proceeds with the upgrade
β (Optional) Runs post-upgrade tasks (e.g., send email, remove banner)
π§Ύ Question
You have previously installed a Helm chart for a web application. Now, perform the following tasks:
Create a new Kubernetes Job named
upgrade-hook
.This job should be configured as a Helm hook that runs after the chart is upgraded (i.e., use the
post-upgrade
hook).The container image to be used should be
alpine
.The job should output the message:
Successful Upgradation
.Update the Helm chart with:
App version:
2.4.51
Chart version:
0.2
Finally, upgrade the existing Helm release named
httpd
using the updated chart.
β Solution
π Step 1: Update Chart.yaml
Open the Chart.yaml
file of your Helm chart (e.g., webapp/Chart.yaml
) and update it as follows:
apiVersion: v2
name: webapp
description: An Apache Application
type: application
version: 0.2 # Chart version
appVersion: 2.4.51 # App version
π Step 2: Create the Hook Job (upgrade-job.yaml
)
Inside your chart's templates/
directory, create a file named upgrade-job.yaml
with the following content:
apiVersion: batch/v1
kind: Job
metadata:
name: upgrade-hook
annotations:
"helm.sh/hook": post-upgrade
spec:
template:
spec:
containers:
- name: upgrade-hook
image: alpine
command: ["echo", "Successful Upgradation"]
restartPolicy: Never
backoffLimit: 4
β This job is configured to run only after a Helm upgrade, and it simply prints a success message.
π» Step 3: Upgrade the Helm Release
Now, run the following command to upgrade your Helm release:
helm upgrade httpd webapp/
This will:
Upgrade the chart named
webapp
Execute the
upgrade-hook
job after the upgrade (due to thepost-upgrade
hook)
β (Optional) Verify Job Output
To check the output of the upgrade-hook
job:
kubectl get jobs
kubectl logs job/upgrade-hook
π¦ Helm Chart Packaging, Signing, and Verification
β 1. Packaging a Helm Chart
Purpose:
To compress your chart directory into a distributable .tgz
archive.
Command:
helm package ./nginx-chart
Result:
A packaged chart file is created, e.g.,
nginx-chart-0.1.0.tgz
The version
0.1.0
is defined inside the chartβsChart.yaml
The
.tgz
is a tarball compressed with gzip used for storage, distribution, and installation.
π 2. Why Sign Charts?
Purpose:
To ensure the integrity and authenticity of the chart.
Scenario:
Imagine a user downloads a chart from a Helm repository.
If the repository is compromised or tampered with, malicious content may be delivered.
Signing allows the user to verify that:
The chart has not been modified
It was created by a trusted developer
How it works:
You sign your chart using your private GPG key.
This creates a
.prov
file that includes:The SHA256 hash of the
.tgz
Your GPG signature
π 3. Creating a GPG Key
GPG (GNU Privacy Guard) is used for generating cryptographic keys.
Method 1: Quick (for testing or short-term use)
gpg --quick-generate-key "John Smith"
- Automatically creates a key pair with default settings.
Method 2: Full (recommended for production)
gpg --full-generate-key
Offers custom configuration:
Key type (RSA, ECC)
Expiration date
Email address
Passphrase
Export Secret Key for Helm (Optional):
gpg --export-secret-keys > ~/.gnupg/secring.gpg
πΈ Helm uses the
secring.gpg
file to locate your private key.
ποΈ 4. Signing the Helm Chart
Command:
helm package --sign --key 'John Smith' --keyring ~/.gnupg/secring.gpg ./nginx-chart
What it does:
Packages the chart and adds a
.prov
fileUses your private key to sign the chart
The
.prov
file includes:Chart metadata
SHA256 hash
GPG signature block
πΈ The
.prov
file must be distributed along with the.tgz
.
π 5. Understanding the Provenance (.prov
) File
This file contains:
Metadata from
Chart.yaml
SHA256 hash of the chart archive
The GPG signature that proves the authenticity of the signer
You can view the SHA256 hash of the chart like this:
sha256sum nginx-chart-0.1.0.tgz
π§ͺ 6. Verifying a Signed Chart
Before verification, ensure you have the public key of the chart signer.
Step 1: Export the public key from your GPG setup
gpg --export 'John Smith' > mypublickey
Step 2: Verify the signed chart
helm verify --keyring ./mypublickey ./nginx-chart-0.1.0.tgz
Output (if successful):
Signed by: John Smith
Chart Hash Verified: sha256:...
πΈ This proves the chart came from John Smith and has not been modified.
π 7. Uploading to a Repository
When distributing your Helm chart:
Upload both:
nginx-chart-0.1.0.tgz
(chart archive)nginx-chart-0.1.0.tgz.prov
(provenance/signature file)
Your users should also be able to obtain your public GPG key, which they can import like this:
gpg --recv-keys --keyserver keyserver.ubuntu.com <KEY_ID>
π 8. Installing a Chart with Signature Verification
Users can install a chart and verify its signature during installation:
helm install --verify nginx-chart ./nginx-chart-0.1.0.tgz
πΈ This installation will fail if:
The
.prov
file is missingThe public key is not trusted or missing
The chart has been tampered with
π§Ύ Example Workflow Summary
# Step 1: Package the chart
helm package ./nginx-chart
# Step 2: Generate GPG key (if not done)
gpg --quick-generate-key "John Smith"
# Step 3: Export secret key (for Helm)
gpg --export-secret-keys > ~/.gnupg/secring.gpg
# Step 4: Sign the chart
helm package --sign --key 'John Smith' --keyring ~/.gnupg/secring.gpg ./nginx-chart
# Step 5: Export public key (for others to verify)
gpg --export 'John Smith' > mypublickey
# Step 6: Verify the signed chart
helm verify --keyring ./mypublickey ./nginx-chart-0.1.0.tgz
# Step 7: Install with verification
helm install --verify nginx-release ./nginx-chart-0.1.0.tgz
π¦ Uploading Helm Charts and Using a Custom Chart Repository
Helm allows us to package and distribute charts via a custom chart repository, similar to how package managers like npm or pip operate. Below is a step-by-step guide on how to prepare and host your own Helm charts using index.yaml
, and then use them in deployments.
π§ Step 1: Organize Chart Files
First, we package and collect our chart files (including the provenance file if available):
$ ls
nginx-chart/ nginx-chart-0.1.0.tgz nginx-chart-0.1.0.tgz.prov
Create a dedicated directory to host your packaged charts:
$ mkdir nginx-chart-files
$ cp nginx-chart-0.1.0.tgz nginx-chart-0.1.0.tgz.prov nginx-chart-files/
π Step 2: Generate index.yaml
for the Chart Repository
Use the helm repo index
command to generate an index.yaml
file, which acts as the index for your Helm chart repository. Specify the base URL where the charts will be hosted.
$ helm repo index nginx-chart-files/ --url https://example.com/charts
After this, youβll see the following inside the nginx-chart-files
folder:
$ ls nginx-chart-files
index.yaml nginx-chart-0.1.0.tgz nginx-chart-0.1.0.tgz.prov
This index.yaml
file will contain metadata for your chart, such as:
apiVersion: v1
entries:
nginx-chart:
- apiVersion: v2
appVersion: 1.16.0
created: "2021-12-01T15:29:35.073405539Z"
description: A Helm chart for Kubernetes
digest: 2c83c29dc4c56d20c45c3de8eff521fbfb6ef6c0b66854a6f4b5539bebcff879
maintainers:
- email: john@example.com
name: john smith
name: nginx-chart
type: application
urls:
- https://charts.bitnami.com/bitnami/nginx-chart-0.1.0.tgz
version: 0.1.0
generated: "2021-12-01T15:29:35.047718855Z"
Note: The
urls
field must point to the downloadable path for your.tgz
chart file.
π Step 3: Host the Charts
Upload the contents of the nginx-chart-files
folder (including index.yaml
, .tgz
, and .prov
) to a public URL, e.g., a cloud storage bucket or a web server like:
https://example-charts.storage.googleapis.com
β Step 4: Add the Chart Repository to Helm
Add the newly hosted chart repository to your local Helm environment:
$ helm repo add our-cool-charts https://example-charts.storage.googleapis.com
List the repositories to confirm it was added:
$ helm repo list
NAME URL
bitnami https://charts.bitnami.com/bitnami
our-cool-charts https://example-charts.storage.googleapis.com
π Step 5: Install the Chart from the Custom Repo
Now, you can install your chart just like you would from any official repository:
$ helm install my-new-release our-cool-charts/nginx-chart
This command will fetch the nginx-chart
from your custom repository and deploy it as a new release named my-new-release
.
Subscribe to my newsletter
Read articles from Arindam Baidya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
