Helm Chart: quick start your app deployment on Kubernetes

Pankaj Kumar
10 min readJul 19, 2021
Photo by Loik Marras on Unsplash

What is helm?

Consider you need to deploy a complex microservices application on Kubernetes. Most likely you will end up maintaining many YAML files for each microservices. Maintaining those YAML files is complex and error-prone. This is where Helm comes into the picture.

Helm is an application package manager for Kubernetes (think apt or yum or chocolatey for Windows). Helm downloads, installs and deploys apps for you on the Kubernetes.

Helm helps you manage Kubernetes applications — Helm Charts helps you define, install, and upgrade even the most complex Kubernetes application.

Charts are easy to create, version, share, and publish — so start using Helm and stop the copy-and-paste.

Helm is a graduate project in the CNCF and is maintained by the Helm community.

Using Helm

  • You can install, upgrade, and delete installation.
  • You can search the repository to find what Kubernetes applications are available.
  • You can configure applications prior to installing them.
  • You can see what is already installed and how it is configured.

The focus of this article is Helm 3. Earlier version Helm 2 is not recommended anymore.

What is a helm chart?

Helm charts are Kubernetes YAML manifests combined into a package. A chart is a set of files and directory that defines the resources to be installed on the Kubernetes.

Creating your first chart

After installing helm, run command helm create app. This create directory /app. The app directory structure looks like this:

charts/ #
.helmignore #
  • charts: a directory containing any charts upon which this chart depends.
  • templates: a directory of templates that, when combined with values, # will generate valid Kubernetes manifest files.
  • .helmignore: defines all files to ignore when packaging chart.
  • Chart.yaml: a YAML file containing information about the chart.
  • values.yaml: the default configuration values for this chart

Chart Definition

If you peek inside Chart.yaml then you’ll see something like (sans comments):

apiVersion: v2 
name: app
description: A Helm chart for Kubernetes
type: application version: 0.1.0
appVersion: "1.16.0"
  • apiVersion: v2 denotes Helm 3.
  • Version: This is the chart version. You are supposed to make changes to the version every time you make changes to the chart.
  • Type: A chart can be either ‘application’ or ‘library’. Application charts are what you deploy on Kubernetes. You can think of a library chart as a utility chart that provides utility functions for the other charts. You can include a library chart with other charts.
  • appVersion: the version number of your application. You should increment the version each time you make changes to the application.

Default Configuration

The values.yaml contains the default value used by the chart. For example, by default ‘ helm create app' command creates an NGINX deployment. You can verify that in value.yaml.

replicaCount: 1 
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""

It’s possible to override default values but more about this later.


The template directory contains all the manifest files needed for Kubernetes application deployment. A templated file contains a template directive which can be resolved by providing configuration. For example, deployment.yaml has a template directive .Values.replicaCount, that is resolved from replicaCount: 1 of values.yaml.

apiVersion: apps/v1 
kind: Deployment
name: {{ include "app.fullname" . }}
{{- include "app.labels" . | nindent 4 }}
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }} {{- end }}

A template directive is enclosed in {{ and }} blocks.

Installing a chart

To install a chart run command:

helm install my-app app

This will install a chart app with the installation name my-app.

An installation of a chart is a specific instance of the chart. You can have many installations of the same chart. When you run the helm install command, you need to give it an installation name as well as the chart name.

Running above command prints:

NAME: my-app 
LAST DEPLOYED: Sat Jul 3 12:16:04 2021
NAMESPACE: default
STATUS: deployed
Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=app,app.kubernetes.io/instance=my-app" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT

You can validate Helm installation by running the command kubectl get deployment:

my-app 1/1 1 1 9s

or by using command helm list:

my-app default 1 deployed app-0.1.0 1.16.0

To uninstall an installation run command helm uninstall my-app. This will remove all resources associated with a particular installation.

A Helm chart installation can contain many Kubernetes resources. Kubernetes sees each of these as a discrete resource. But in Helm’s view, all of the resources defined by a chart are related. So when you run the uninstall command it removes all Kubernetes resources associated with that particular installation. In the above case Helm not only removes deployment but also service associated with the installation ‘my-app’.

When you run command helm install my-app app, Helm installs the application my-app on the Kubernetes cluster. But how does Helm knows about the Kubernetes cluster?

How does the Helm know about which Kubernetes cluster to connect?

As Helm interacts directly with the Kubernetes API server it needs to know about the Kubernetes cluster. Helm does this automatically by reading the same configuration files used by kubectl. It will try to find this information by reading the environment variable $KUBECONFIG. If that is not set, it will look in the same default locations that kubectl looks in.

You can also override these settings with environment variables ( HELM_KUBECONTEXT) and command-line flags (--kube-context). It's recommended that you use Kubectl to manage Kubernetes credentials and let Helm autodetect these settings.

Installing a third party chart

One of the biggest advantages of Helm is that you can use charts (also called packages) published by other authors. Charts are hosted in the chart repository. A Repository is a place where charts can be collected and shared. It’s like maven repository, but for Kubernetes packages. There are many charts repository and the easiest way to find chart repositories by going to the Artifact Hub. If you search MySQL on the Artifact Hub, you will find chart repositories hosting MySQL charts.

Before you start using the MySQL chart published by Bitnami, you need to tell Helm about the Bitnami repo as:

helm repo add bitnami https://charts.bitnami.com/bitnami

You can list all repositories, which your Helm knows about, as:

helm repo list NAME    URL 
bitnami https://charts.bitnami.com/bitnami

You can search the chart as:

helm search repo mysql 

Installing a chart

You can install the MySQL chart by running the command helm install <installation_name> <chart_name> as:

helm install appdb bitnami/mysql NAME: appdb 
LAST DEPLOYED: Sat Jul 3 16:24:19 2021
NAMESPACE: default
STATUS: deployed
** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace default Services:
echo Primary: appdb-mysql.default.svc.cluster.local:3306

You can run helm list to validate MySQL deployment as:

appdb default 1 deployed mysql-8.7.0 8.0.25

Configuring Values

When you installed the MySQL package by running the command helm install appdb bitnami/mysql, it installed MySQL with some default values. You can see the default values in the MySQL chart definition. You can also see the default values of the Helm installation by running the command helm inspect values bitnami/mysql.

helm inspect values bitnami/mysql ## Global Docker image parameters 
## Please, note that this will override the image parameters, including dependencies, configured to use the global value
## Current available global Docker image parameters: imageRegistry and imagePullSecrets
# global:
# imageRegistry: myRegistryName
# imagePullSecrets:
# - myRegistryKeySecretName
# storageClass: myStorageClass
## Bitnami MySQL image
## ref: https://hub.docker.com/r/bitnami/mysql/tags/

You can override the default values by providing a values.yaml file with --values flag as:

helm install appdb bitnami/mysql --values values.yaml

--values flag can be set with both helm install and upgrade commands.

You can also use --set flag to override default values. If you use --set flag with values.yaml, to override the same value, then --set flag gets precedence.

helm upgrade appdb bitnami/mysql --values values.yaml --set auth.rootPassword=$ROOT_PASSWORD 
Release "appdb" has been upgraded. Happy Helming!
NAME: appdb
LAST DEPLOYED: Tue Jul 6 08:32:41 2021
NAMESPACE: default
STATUS: deployed

whereas values.yaml contains:

auth.database: product_db

It is recommended as a best practice to use values.yaml instead of --set flag. The reason for that is you can version values.yaml in version control.

Helm Release

If you run the helm list command then you'll see:

appdb default 2 deployed mysql-8.7.0 8.0.25

Notice that revision of appdb is marked as 2 with status deployed. When you upgraded a chart, Helm creates a new Release. A Release is an instance of a chart running in a Kubernetes cluster. You can think of a release as a particular combination of configuration and version.

When you run the helm install command, Helm creates a release record. These release records are stored as Kubernetes secret.

As you can see, Helm creates a secret record for each release. You can get more information about a release by describing secret as:

Helm History and Rollbacks

You can use helm history to see the status of chart releases.

You will notice that version 1 is marked superseded and version 2 is marked deployed. The history command also lists the error message in case of a failed deployment.

If you need to roll back to the previous revision, you can do that using helm rollback <revision>.

helm rollback appdb 1 Rollback was a success! Happy Helming!

If you run the helm history command again you'll notice that Helm has created a new release and marked earlier release as superseded.

Dry Run

Helm provides you the ability to debug helm install and upgrade command. You can do a dry run before applying changes to the Kubernetes using flag --dry-run.

While installing a release Helm roughly performs these steps.

  1. Load entire chart including dependencies.
  2. Parse the value.
  3. Execute template and generate YAML. In this step Helm can contact API Server.
  4. Parse the YAML into the Kubernetes object.
  5. Send to Kubernetes.

The dry run performs all steps except step 5.

During dry run Helm contacts Kubernetes API Server for validation. You must have a Kubernetes cluster credential to execute a dry run.

If you don’t have credentials for the Kubernetes server, you can use the helm template command to generate template YAML. As Helm does not contact the API server output of the commands --dry-run and template can differ.

Creating chart

Let’s go through step by step process of creating a chart to deploy the app mentioned in the article Getting started with Kind.

Run command helm create product-svc. This creates a chart product-svc under directory product-svc. To customize, you can modify the file values.yaml.


To run three replicas of the pod, modify values.yaml to set replicaCount to 3.

## Old replicaCount: 1 
## New replicaCount: 3

Modify the image section to set the value of repository and tag as:

As product-svc exposes port 8080, change templates/deployment.yaml and set containerPort to 8080. Also, product-svc doesn't expose '/' endpoint, we need to remove entries for readinessProbe and livenessProbe.


As Ingress is defined without a host (listed below), you have to make a couple of changes to make Ingress work.

Enable Ingress by setting the field enable to true in values.yaml and remove host entry.

And then from /templates/ingress.yaml remove host entry.

You can validate generated YAML by running the command helm install product product-svc --dry-run.

If you are running a local cluster then you can install the Ingress controller using this guide.

Chart Dependency

Dependencies between packages are a very common concern in any installation. Helm solves this by using chart dependencies. Suppose, you need to deploy MySQL DB with your product microservices then you add MySQL chart dependencies in chart.yaml as:

name: mysql
version: ^8.7.0
repository: https://charts.bitnami.com/bitnami

‘^’ in ‘8.7.0’ denotes the caret range of semantic versioning. This means >=8.7.0 < 9.0.0. The range is a preferred way of defining dependency in the Helm chart. The range helps to pull the latest charts for bugs and security fixes.

To update dependency, run command `helm dependency update`.

If you check the charts subdirectory, you will notice that Helm has downloaded mysql-8.7.1.tgz.

Locking chart to a specific version

During dependency update Helm performs the following steps.

  1. Helm reads repository metadata to chart version. From metadata and specified range, it finds the best match.
  2. Helm writes resolved information Chart.lock file. This file is used to rebuild the dependencies to an exact version.
  3. Once, specific version is resolved, Helm downloads the dependent charts and puts them in the charts subdirectory.

You can run command helm dependency build to download dependencies. This is useful when you have Chart.lock file but no dependencies charts subdirectory.

Defining values for the dependent chart

You can pass values from the main chart to the dependent chart. To do that create a new section with the name of the dependent chart in values.yaml file of the main chart.

auth.database: product_db

To deploy the chart with dependency, you can run helm upgrade or uninstall and install the product chart. You can confirm MySQL deployment by running the command kubectl get pods.

When to use chart dependency?

Chart dependencies are useful when you want to upgrade dependent applications together. For example, if each of your microservice needs a separate instance of MySQL. In this case upgrade of your application, including dependent chart, becomes atomic. This is a preferred approach if you need to distribute chart to other.

If you run helm list then you’ll notice Helm lists only the main chart, not the dependent chart.

Another way of installing dependencies is to install each chart separately. In this scenario, you can upgrade each installation of the chart separately. This is the preferred approach if you create and run charts within your organization.

Chart Example

You can find the chart of the example mentioned in the article at GitHub .


Helm is much more than the package manager of the Kubernetes. Helm chart is a YAML manifests combined into a package. A chart is a set of files and directory that defines the resources to be installed on the Kubernetes. One of the biggest advantages of Helm is that you can use charts (also called packages) published by other authors. Charts are hosted in the chart repository. A Repository is a place where charts can be collected and shared. The easiest way to find chart repositories by going to the Artifact Hub. You can deploy a third party as a stand-alone chart or as a chart dependency.

Further Reading

Originally published at https://techdozo.dev.



Pankaj Kumar

Software Architect @ Schlumberger ``` Cloud | Microservices | Programming | Kubernetes | Architecture | Machine Learning | Java | Python ```