Start your free 14-day ContainIQ trial

Helm Charts: Kubernetes Tutorial and Examples

Managing complex Kubernetes deployments is no small feat and that’s where Helm can help. In this guide, you’ll learn how Helm charts fit into their Kubernetes workflow.

July 13, 2022
Karl Hughes
Software Engineer, & Author

Because Kubernetes makes container-orchestration incredibly easy, it’s become a mainstay in the cloud-native ecosystem, but dealing with Kubernetes objects can be complex.

A typical application deployed to Kubernetes will have objects like deployments, services, Pods, configmaps, secrets, hpa, ingress, etc., and with its declarative nature, you define everything through YAML files.

Now imagine having to manage and maintain the YAML files for each environment. That’s where Helm comes in. It’s a widely known package manager for your Kubernetes workloads. Helm Charts help you define, install, and upgrade complex Kubernetes applications.

In this article, you’ll learn how Helm Charts fit into a Kubernetes workflow and review examples for how they can be used to benefit your organization.

Why You Need Helm

DevOps engineers frequently use package managers like yum, Homebrew, and Chocolatey to install software.

Helm is the only package manager specifically for Kubernetes applications. You can package your applications as a Helm Chart, and then install, update, and roll back your Kubernetes applications using Helm. In addition, you can use production-ready, pre-packaged charts for popular software like NGINX, MySQL, and MongoDB from a stable chart repository like Bitnami or ArtifactHUB.

What Makes Helm Architecture Superior

The original version of Helm followed a client-server architecture, which required two separate installations; On the client-side, the CLI, and on the server-side, a component named Tiller. Because of some security concerns, Tiller was removed, and Helm v3 is a client-only utility.

Helm provides numerous features for Kubernetes applications including:

  1. Deploying Kubernetes packages through a single CLI command. If you have a dependency on other charts, you can include that as well.
  2. Helm allows you to customize application configurations during deployment so that you can reuse one Helm Chart across multiple environments.
  3. It makes it easy to streamline CI/CD pipeline for Kubernetes workloads.
  4. It simplifies the rollback of your Kubernetes applications in case of issues in deployment. Helm does this by automatically maintaining all the versions of your releases.
  5. Helm enables teams to automate the pre- and post-deployment actions with its CI/CD integration hooks.
K8s Metrics, Logging, and Tracing
Monitor the health of your cluster and troubleshoot issues faster with pre-built dashboards that just work.
Start Free Trial Book a Demo

How to Use Helm Charts in Practice

Let’s begin by first installing Helm. You can install Helm on Windows, macOS, and Linux using standard package managers like Chocolatey, Homebrew, or APT.

On macOS, you can use the Homebrew command <terminal inline>brew install helm<terminal inline> to install.

Or, on Windows, you can use <terminal inline>choco install kubernetes-helm<terminal inline> to install using Chocolatey.

Helm also provides an installer script that will download the latest version for you.


$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh

After installing Helm on your operating system, verify the installation using <terminal inline>helm version<terminal inline>. You will see the following output after running the command:


$ helm version
version.BuildInfo{Version:"v3.7.1", GitCommit:"1d11fcb5d3f3bf00dbe6fe31b8412839a96b3dc4", GitTreeState:"clean", GoVersion:"go1.16.9"}

The following is a list of supported commands with Helm CLI:


Usage:
  helm [command]

Available Commands:
  completion  generate autocompletion scripts for the specified shell
  create      create a new chart with the given name
  dependency  manage a chart's dependencies
  env         helm client environment information
  get         download extended information of a named release
  help        Help about any command
  history     fetch release history
  install     install a chart
  lint        examine a chart for possible issues
  list        list releases
  package     package a chart directory into a chart archive
  plugin      install, list, or uninstall Helm plugins
  pull        download a chart from a repository and (optionally) unpack it in local directory
  repo        add, list, remove, update, and index chart repositories
  rollback    roll back a release to a previous revision
  search      search for a keyword in charts
  show        show information of a chart
  status      display the status of the named release
  template    locally render templates
  test        run tests for a release
  uninstall   uninstall a release
  upgrade     upgrade a release
  verify      verify that a chart at the given path has been signed and is valid
  version     print the client version information

Let’s install NGINX using a pre-packaged Helm Chart on your local Kubernetes cluster. Use <terminal inline>helm search repo chart-name<terminal inline> to look for the chart in the local repository.


$ helm search repo nginx
WARNING: Repo "bitnami" is corrupt or missing. Try 'helm repo update'.
WARNING: open C:\Users\mypc\AppData\Local\Temp\helm\repository\bitnami-index.yaml: The system cannot find the file specified.
No results found

As you can see, the local helm repository is not updated, and it fails to find the chart. You can fix this by running the command <terminal inline>helm repo update<terminal inline>.


$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈

Then rerun the command <terminal inline>helm search repo nginx<terminal inline> to verify that you can now search for the NGINX Helm Chart.

$ helm search repo nginx

NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/nginx 9.5.13 1.21.4 Chart for the nginx server
bitnami/nginx-ingress-controller 9.0.6 1.0.5 Chart for the nginx Ingress controller
bitnami/kong 4.1.9 2.6.0 Kong is a scalable, open source API layer (aka ...

You should see all the charts have NGINX in their name.

Now, choose the <terminal inline>bitnami/nginx<terminal inline> chart name and install it using the <terminal inline>helm install nginx bitnami/nginx command<terminal inline>.

There are five different ways you can express the chart you want to install:

  1. By chart reference: <terminal inline>helm install mymaria example/mariadb<terminal inline>
  2. By path to a packaged chart: <terminal inline>helm install mynginx ./nginx-1.2.3.tgz<terminal inline>
  3. By path to an unpacked chart directory: <terminal inline>helm install mynginx ./nginx<terminal inline>
  4. By absolute URL: <terminal inline>helm install mynginx https://example.com/charts/nginx-1.2.3.tgz<terminal inline>
  5. By chart reference and repo url: <terminal inline>helm install --repo https://example.com/charts/ mynginx nginx<terminal inline>

Before you continue with installing the Helm Chart, make sure you have a local Kubernetes cluster up and running.

The following is the output of running <terminal inline>helm install nginx bitnami/nginx<terminal inline>:


$ helm install nginx bitnami/nginx
NAME: nginx
LAST DEPLOYED: Wed Nov 17 01:12:56 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

NGINX can be accessed through the following DNS name from within your cluster:

    nginx.default.svc.cluster.local (port 80)

To access NGINX from outside the cluster, follow these steps:

1. Get the NGINX URL by running these commands:

  > NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w nginx'

    export SERVICE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].port}" services nginx)
    export SERVICE_IP=$(kubectl get svc --namespace default nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "http://${SERVICE_IP}:${SERVICE_PORT}"

Verify the installation by running <terminal inline>kubectl<terminal inline>.

kubectl get all

NAME READY STATUS RESTARTS AGE
pod/nginx-7c47855f86-wk4pt 1/1 Running 0 35s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
service/nginx LoadBalancer 10.109.204.224 <pernding> 80:30682/TCP 35s

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 36s

NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-7c47855f86 1 1 1 36s

You’ll notice from the output above that Helm has created the service, Pod, deployment, and replica set for us.

Run the <terminal inline>helm list<terminal inline> command to list down the deployed or failed releases.

$ helm list

NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
nginx default 1 2021-11-17 01:12:56.74093 +0530 IST deployed nginx-9.5.2 1.21.1

Since you are using minikube as a local Kubernetes cluster, you can use the <terminal inline>minikube service nginx<terminal inline> command to expose the service for external access.

$ minikube service nginx

|-----------| ------- |--------------| ----------------------------|
NAMESPACE NAME TARGET PORT URL
|-----------| ------- |--------------| ----------------------------|
default nginx http/80 http://192.168.64.20:30682
|-----------| ------- |--------------| ----------------------------|

🎉 Opening service default/nginx in default browser...

Use the URL mentioned in the preceding output to access your application:

NGINX image
NGINX image

Now you have deployed a pre-packaged Helm Chart.

You can also create a Helm Chart specific to your application using the <terminal inline>helm create<terminal inline> command. Your output would be:


$ helm create demo
Creating demo
$ tree demo
demo
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

An NGINX image is configured by default, but you can tweak all the configurations based on your needs by editing the <terminal inline>values.yaml<terminal inline> file and installing it using the <terminal inline>helm install<terminal inline> command. Template files under the <terminal inline>/templates<terminal inline> directory contain the placeholders. Their values are replaced by <terminal inline>values.yaml<terminal inline>.

For example, maybe you want to limit the amount of hardware resources your application can utilize. You can add the following changes in your <terminal inline>values.yaml<terminal inline> file.


resources:
 # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
   limits:
     cpu: 100m
     memory: 128Mi
   requests:
     cpu: 100m
     memory: 128Mi

If you would like to change the <terminal inline>imagePullPolicy<terminal inline> to <terminal inline>Always<terminal inline> from the default <terminal inline>IfNotPresent<terminal inline> add the following changes to your <terminal inline>values.yaml<terminal inline> file.


image:
  repository: nginx
  pullPolicy: Always

Helm Tips and Best Practices

Before incorporating Helm Charts into your Kubernetes workflow, keep in mind the following best practices to ensure your processes are efficient and practical.

Use heml template to Verify

To make sure that everything is as expected before deploying your chart to the target Kubernetes cluster, use the <terminal inline>helm template<terminal inline> command. This will render chart templates locally and display the output.

Any values that would normally be looked up or retrieved in-cluster will be faked locally, and the command will finally display each YAML file created by all the templates.

Use heml lint to Test

You can use <terminal inline>helm lint<terminal inline> to run a series of tests to verify that the chart is well-formed. If the linter encounters things that will cause the chart to fail installation, it will emit ERROR messages. If it encounters issues that break with convention or recommendation, it will emit WARNING messages.

Label Your Resources

Labels can be used to find your resources created by Helm releases instantly. The easiest way to define labels is using the <terminal inline>helpers.tpl<terminal inline> file.

Use Helm Functions to Simplify

Helm functions simplify operations inside template files. We typically combine it with pipelines, and you can control flow in your Helm templates.

For example, if the value for an image tag is not provided in a template file, it will use the chart app version as an image tag. Here <terminal inline>default<terminal inline> is the function.


 image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}

Limitations of Helm Charts

As with any new tool, there is a learning curve involved with Helm. It’s not easy to create and deploy your first chart.

Charts are also an extra piece of code that you have to manage and take care of. This includes the overhead to manage, maintain, and store in a chart repository. Helm can be excessive for simpler deployments.

Maintaining charts alone may not be a significant issue, but using charts managed by others can be. Are you comfortable using charts managed by third parties? What if the chart uses an old image with known vulnerabilities? Keep these factors in mind before using Helm.

In addition, troubleshooting issues on an application with a lot of Kubernetes resources can be difficult with Helm.

A Helm Alternative

If you want to consider a Helm alternative, then Kustomize is worth exploring. It’s a Kubernetes native configuration management open-source tool. Contrary to Helm, Kustomize introduces a template-free way to customize application configuration. You don’t have to install it separately, as it’s baked into <terminal inline>kubectl<terminal inline>. You can use it by simply supplying the -k flag with the <terminal inline>kubectl apply<terminal inline> command.

Conclusion

With Helm, deploying and reverting changes for your Kubernetes workloads is as easy as pressing a button.

If you are a DevOps engineer trying to install applications developed internally or with third-party software like databases, you should consider Helm. It’s easier to share applications packaged as charts with others in the organization, and you can deploy Kubernetes packages through a single CLI command.

Helm allows you to customize application configurations during deployment and makes it easy to streamline CI/CD pipelines for Kubernetes workloads. If you are looking for help in managing complex Kubernetes deployments, Helm can help.

Start your free 14-day ContainIQ trial
Start Free TrialBook a Demo
No card required
Karl Hughes
Software Engineer, & Author

Karl is the Founder & CEO of Draft where he works to create engaging and thoughtful content for software engineers. Prior to his current role, he was the CTO at The Graide Network where he led an incremental transition from legacy offshore web application to microservice architecture. Karl has a Bachelors in Mechanical Engineering from the University of Tennessee at Knoxville.

READ MORE