Helm to the rescue!
Over time, the Kubernetes community discovered that creating and maintaining Kubernetes resources to deploy applications is difficult. This prompted the development of a simple yet powerful tool that would allow teams to overcome the challenges posed by deploying applications on Kubernetes. The tool that was created is called Helm. Helm is an open source tool used for packaging and deploying applications on Kubernetes. It is often referred to as the Kubernetes package manager because of its similarities to any other package manager you would find on your favorite operating system (OS). Helm is widely used throughout the Kubernetes community and is a CNCF graduated project.
Given Helm’s similarities to traditional package managers, let’s begin exploring Helm by first reviewing how a package manager works.
Understanding package managers
Package managers are used to simplify the process of installing, upgrading, reverting, and removing a system’s applications. These applications are defined as packages that contain metadata around target software and its dependencies.
The idea behind package managers is simple. First, the user passes the name of a software package as an argument. The package manager then performs a lookup against a repository to see whether that package exists. If it is found, the package manager installs the application defined by the package and its dependencies to specified locations on the system.
Package managers make managing software very easy. As an example, let’s imagine you wanted to install htop
, a Linux system monitor, to a Fedora machine. Installing this would be as simple as typing a single command, as follows:
dnf install htop --assumeyes
This instructs dnf
, the Fedora package manager, to find htop
in the Fedora package repository and install it. dnf
also takes care of installing the htop
package’s dependencies, so you don’t have to worry about installing its requirements beforehand. After dnf
finds the htop
package from the upstream repository, it asks you whether you’re sure you want to proceed. The --assumeyes
flag automatically answers yes to this question and any other prompts that dnf
may potentially ask.
Over time, newer versions of htop
may appear in the upstream repository. dnf
and other package managers allow users to efficiently upgrade to new versions of the software. The subcommand that allows users to upgrade using dnf
is upgrade
, as illustrated here:
dnf upgrade htop --assumeyes
This instructs dnf
to upgrade htop
to its latest version. It also upgrades its dependencies to the versions specified in the package’s metadata.
While moving forward is often better, package managers also allow users to move backward and revert an application to a prior version if necessary. dnf
does this with the downgrade
subcommand, as illustrated here:
dnf downgrade htop --assumeyes
This is a powerful process because the package manager allows users to quickly roll back if a critical bug or vulnerability is reported.
If you want to remove an application completely, a package manager can take care of that as well. dnf
provides the remove
subcommand for this purpose, as illustrated here:
dnf remove htop --assumeyes
In this section, we reviewed how the dnf
package manager on Fedora can be used to manage a software package. Helm, as the Kubernetes package manager, is similar to dnf
, both in its purpose and functionality. While dnf
is used to manage applications on Fedora, Helm is used to manage applications on Kubernetes. We will explore this in greater detail next.
The Kubernetes package manager
Given that Helm was designed to provide an experience similar to that of package managers, experienced users of dnf
or similar tools will immediately understand Helm’s basic concepts. Things become more complicated, however, when talking about the specific implementation details. dnf
operates on RPM Package Manager (RPM) packages that provide executables, dependency information, and metadata. Helm, on the other hand, works with charts. A Helm chart can be thought of as a Kubernetes package. Charts contain the declarative Kubernetes resource files required to deploy an application. Similar to an RPM package, it can also declare one or more dependencies that the application needs in order to run.
Helm relies on repositories to provide widespread access to charts. Chart developers create declarative YAML files, package them into charts, and publish them to chart repositories. End users then use Helm to search for existing charts to deploy onto Kubernetes, similar to how end users of dnf
will search for RPM packages to deploy to Fedora.
Let’s go through a basic example. Helm can be used to deploy Redis, an in-memory cache, to Kubernetes by using a chart from an upstream repository. This can be performed using Helm’s install
command, as illustrated here:
helm install redis bitnami/redis --namespace=redis
This would install the redis
chart from the bitnami
repository to a Kubernetes namespace called redis
. This installation would be referred to as the initial revision, or the initial installation of a Helm chart.
If a new version of the redis
chart becomes available, users can upgrade to the new version using the upgrade
command, as follows:
helm upgrade redis bitnami/redis --namespace=redis
This would upgrade redis
to meet the specification defined by the newer redis
chart.
With OSs, users should be concerned about rollbacks if a bug or vulnerability is found. The same concern exists with applications on Kubernetes, and Helm provides the rollback
command to handle this use case, as illustrated here:
helm rollback redis 1 --namespace=redis
This command would roll redis
back to its first revision.
Finally, Helm provides the ability to remove redis
altogether with the uninstall
command, as follows:
helm uninstall redis --namespace=redis
Compare dnf
and Helm’s subcommands, and the functions they serve in the following table. Notice that dnf
and Helm offer similar commands that provide a similar user experience (UX):
|
Helm subcommands |
Purpose |
|
|
Install an application and its dependencies. |
|
|
Upgrade an application to a newer version. Upgrade dependencies as specified by the target package. |
|
|
Revert an application to a previous version. Revert dependencies as specified by the target package. |
|
|
Delete an application. Each tool has a different philosophy around handling dependencies. |
Table 1.2 – Purpose of dnf and Helm subcommands
With an understanding of how Helm functions as a package manager, let’s discuss in greater detail the benefits that Helm brings to Kubernetes.
The benefits of Helm
Earlier in this chapter, we reviewed how Kubernetes applications are created by managing Kubernetes resources, and we discussed some of the challenges involved. Here are a few ways Helm can overcome these challenges.
Abstracting the complexity of Kubernetes resources
Let’s assume that a developer has been given the task of deploying a WordPress instance onto Kubernetes. The developer would need to create the resources required to configure its containers, network, and storage. The amount of Kubernetes knowledge required to configure such an application from scratch is high and is a big hurdle for new—and even intermediate Kubernetes users—to clear.
With Helm, a developer tasked with deploying a WordPress instance could simply search for WordPress charts from upstream chart repositories. These charts would have already been written by chart developers in the community and would already contain the declarative configuration required to deploy WordPress and a backing database. Vendor-owned chart repositories also tend to be well maintained, so teams using charts from them would not need to worry about keeping Kubernetes resources up to date. In this regard, developers with this kind of task would act as simple end users that consume Helm in a similar way to any other package manager.
Maintaining an ongoing history of revisions
Helm has a concept called release history. When a Helm chart is installed for the first time, Helm adds that initial revision to the history. The history is further modified as revisions increase via upgrades, keeping various snapshots of how the application was configured at varying revisions.
The following diagram depicts an ongoing history of revisions. The squares in blue illustrate resources that have been modified from their previous versions:
Figure 1.3 – An example of a revision history
The process of tracking each revision provides opportunities for rollback. Rollbacks in Helm are very simple. Users simply point Helm to a previous revision, and Helm reverts the live state to that of the selected revision. Helm allows users to roll back their applications as far as they desire, even back to the very first installation.
Configuring declarative resources in a dynamic fashion
One of the biggest hassles with creating resources declaratively is that Kubernetes resources are static and cannot be parameterized. As you may recall from earlier, this results in resources becoming boilerplate across applications and similar configurations, making it more difficult for teams to configure their applications as code. Helm alleviates these issues by introducing values and templates.
Values can be thought of as parameters for charts. Templates are dynamically generated files based on a given set of values. These two constructs give chart developers the ability to write Kubernetes resources that are generated based on values that end users provide. By doing so, applications managed by Helm become more flexible, have less boilerplate, and are easier to maintain.
Values and templates allow users to do things such as this:
- Parameterize common fields, such as the image name in a deployment and the ports in a service.
- Generate long pieces of YAML configuration based on user input, such as volume mounts in a deployment or the data in a ConfigMap.
- Include or exclude resources based on user input.
The ability to dynamically generate declarative resource files makes it simpler to create YAML-based resources while still ensuring that applications are deployed in an easily reproducible fashion.
Simplifying local and live state synchronization
Package managers prevent users from having to manage all of the intricate details of an application and its dependencies. The same idea holds true with Helm. Using Helm’s values
construct, users can provide configuration changes across an application’s life cycle by managing a small number of parameters instead of multiple full-length YAML resources. When the local state (values/parameters) is updated, Helm propagates the configuration change out to the relevant resources in Kubernetes. This workflow keeps Helm in control of managing intricate Kubernetes details and encourages users to manage the state locally instead of updating live resources directly.
Deploying resources in an intelligent order
Helm simplifies application deployments by having a pre-determined order in which Kubernetes resources need to be created. This ordering exists to ensure that dependent resources are deployed first. For example, Secret instances and ConfigMap instances should be created before deployments, since a deployment would likely consume those resources as volumes. Helm performs this ordering without any interaction from the user, so this complexity is abstracted and prevents users from needing to understand the order in which resources should be applied.
Providing automated life cycle hooks
Similar to other package managers, Helm provides the ability to define life cycle hooks. Life cycle hooks are actions that take place automatically at different stages of an application’s life cycle. They can be used to do things such as the following:
- Perform a data backup on an upgrade.
- Restore data on a rollback.
- Validate a Kubernetes environment prior to installation.
Life cycle hooks are valuable because they abstract complexities around tasks that may not be Kubernetes-specific. For example, a Kubernetes user may not be familiar with the best practices behind backing up a database or may not know when such a task should be performed. Life cycle hooks allow experts to write automation that handles various life cycle tasks and prevents users from needing to handle them on their own.