Helm Best Practices: Proven Strategies to Streamline Kubernetes Deployments Using Helm

2023-06-2118 minute read

To make the most out of Helm, it is important for Helm users to understand the common misconceptions and use best practices. The Helm ecosystem is gives access to thousands of charts from developers worldwide in public Helm repos like Artifact Hub. You can find charts for your needs here and easily add it to your local setup using the Helm repo add command.

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

In this article, we start with some of common Helm terminologies, and discuss best practices while using Subcharts, and more!

Conventions and constraints

Here are some common conventions and constraints when it comes to naming Helm components.

ComponentConvention / Constraint
Chart namesChart names must be lowercase alphanumeric with dashes (-) used to separate words. Uppercase letters, underscores, and dots are not allowed.
Version numbersHelm prefers SemVer 2 for version numbers, except for Docker image tags. When storing SemVer versions in Kubernetes labels, replace the "+" character with "_" since labels do not allow "+".
YAML indentationYAML files should use two spaces for indentation, not tabs.
Helm terminology"Helm" refers to the project as a whole, while "helm" refers to the client-side command.
Chart terminology"chart" does not need to be capitalized, except for "Chart.yaml" file which is case sensitive.
VariablesVariable names should start with a lowercase letter and use camel case to separate words.
YAML structureWhile YAML allows nested values, it is recommended to prefer a flat structure for simplicity and ease of use.
Sharing templatesParent charts and subcharts can share templates. Any defined block in any chart is available to other charts.
Block vs. IncludeIn Helm charts, it is recommended to use "include" instead of "block" for overriding default implementations, as multiple implementations of the same block can result in unpredictable behavior.

Please note that these are recommendations and best practices for Helm charts, but you have flexibility in implementing them based on your specific requirements.

Addressing common misconceptions

Understanding these common misconceptions about Helm will help you leverage its full potential and effectively manage your application deployments on Kubernetes. Helm offers features beyond templating, making it a comprehensive package manager designed specifically for Kubernetes environments.

Helm repositories are recommended but not mandatory. It is possible to deploy a Helm chart directly from the filesystem to a Kubernetes cluster. The minimal Helm pipeline involves checking out a Helm chart from Git, described in uncompressed files, and installing it to the cluster.

However, this breaks down when there is collaboration required in a team setup. It is always recommended to check in helm files and values into a repository with version control.

Chart versions and appVersions

Helm charts have two separate versions: the chart version (defined in Chart.yaml) and the application version (defined as appVersion). These versions are independent and can be incremented in any desired manner. They can be kept in sync or incremented separately based on your requirements and practices.

For example, Grafana app can be v9.3 but chart could be v6.56. There could be a chart update with the same actual app to bump it up to chart v6.57.

Charts and sub-charts

Helm can be used with a single chart containing all the resources for an application. Alternatively, it supports the creation of umbrella charts that have dependencies on other external charts defined in the requirements.yaml file. The decision to use umbrella charts or a single chart depends on your team's process and requirements.

Helm's power beyond templating

Helm is more than just a templating engine. It is a package manager with templating capabilities. Although Helm can be used solely as a templating engine to generate Kubernetes manifests, doing so would disregard the advantages offered by Helm, such as the application registry aspect. Helm provides a way to group manifests, manage releases, and maintain a registry of running applications, which is not readily available with other package managers at present.


Each subchart in Helm has to be a standalone chart. And thus, a subchart cannot be dependent on its parent chart. However, a parent chart can override values of the subchart.

2  ├── Chart.yaml
3  ├── values.yaml
4  ├── charts/
5     ├── mongodb/
6        ├── Chart.yaml
7        ├── values.yaml
8        └── templates/
9            ├── deployment.yaml
10            ├── service.yaml
11            └── ...
12     └── redis/
13         ├── Chart.yaml
14         ├── values.yaml
15         └── templates/
16             ├── deployment.yaml
17             ├── service.yaml
18             └── ...
19  └── templates/
20      ├── deployment.yaml
21      ├── service.yaml
22      └── ...

Managing your dependencies using subcharts

Kubernetes applications consist of interdependent components, so their Helm charts often include multiple resource templates and dependencies. For example, a backend using a database and a message queue may have separate charts for PostgreSQL and RabbitMQ as subcharts.

Three essential elements of creating and configuring subcharts:

  1. Charts folder structure. Add the dependencies under the charts/ directory. In the above example, redis and MongoDB are the subcharts for your app’s chart - mychart.
  2. List your dependencies charts and conditions in the Chart.yaml file.
    2  - name: mongodb
    3    version: 13.15.2
    4    repository: https://charts.bitnami.com/bitnami
    5  - name: redis
    6    version: 17.11.6
    7    repository: https://charts.bitnami.com/bitnami
  3. You can override the values of subcharts in the parent chart with the values.yaml file.
    2  enabled: true
    3      tag: latest
    5  enabled: false

Using global values

Global values in Helm refer to the values that can be accessed by all charts in your chart directory. These are defined in the values.yaml file as global: parameters.

The Values data type has a reserved section called Values.global where global values can be set. Let's set one in our mychart/values.yaml file.

2  drink: coffee
3  food: pizza
5  - mushrooms
6  - cheese
7  - peppers
8  - onions
11  dessert: ice cream
14  salad: caesar

Organizing your charts

When working with Helm charts, organizing your files and documenting your charts is essential for maintaining clarity and facilitating collaboration among teams. This section will provide guidance on two important aspects of chart organization: using labels effectively and documenting your charts.

Using labels

Labels play a critical role in the operations and daily tasks of Kubernetes operators by enabling various functionalities like grouping, resource allocation, load balancing, and scheduling.

When installing multiple resources with a single Helm command, it's important to track the origin of these resources. Labels serve as a convenient way to quickly identify resources created by Helm releases.

To define labels, a common approach is to use the helpers.tpl file:

2Common labels
5{{- define "common.labels" -}}
6app.kubernetes.io/instance: {{ .Release.Name }}
7app.kubernetes.io/managed-by: {{ .Release.Service }}
8{{- end -}}

Subsequently, labels can be included in resource templates using the "include" function:

1apiVersion: apps/v1
2kind: Deployment
4  name: my-queue
5  labels:
6{{ include "common.labels" . | indent 4 }}

By incorporating labels in this manner, you can easily list resources using label selectors. For example, to list all pods of the my-queue deployment managed by a specific Helm release, you can execute the command kubectl get pods -l app.kubernetes.io/instance=[Helm Release Name]. This step is crucial for locating and debugging Helm-managed resources.

Documenting your charts

Effective documentation plays a vital role in maintaining Helm charts. To ensure clarity and facilitate development and usage, consider employing these three approaches:

  • Comments: YAML-based template and values files support comments, enabling the inclusion of explanatory information regarding specific fields.
  • README: A chart's README, written in Markdown format, serves as a comprehensive guide for utilizing the charts. To view the README contents, execute the command: helm show readme [Chart Name].
  • NOTES.txt: Located at templates/NOTES.txt, this special file provides valuable instructions on deploying releases. Similar to resource templates, the content within NOTES.txt can utilize functions and values for dynamic information.

By utilizing these options, you can enhance the documentation of your Helm charts, aiding teams in their development and utilization.

Securing your secrets

Securing sensitive data, such as passwords or keys, is crucial when working with Kubernetes. While Kubernetes provides mechanisms to secure secrets, they are often stored as text files within Helm templates and values.

To address this challenge and ensure the protection of critical information, the helm-secrets plugin can be utilized. This plugin leverages Mozilla SOPS, which supports encryption using various key management services like AWS KMS, Google Cloud KMS, Azure Key Vault, and PGP.

💡 To explore other ways to manage Kubernetes secrets, check out this article.

Suppose you have gathered your sensitive data in a file called secrets.yaml, containing values for PostgreSQL:

2  postgresqlUsername: postgresdb3
3  postgresqlPassword: gzMqXv3Wj5

By using the helm-secrets plugin, you can encrypt the file as follows:

1$ helm secrets enc secrets.yaml
2Encrypting secrets.yaml
3Encrypted secrets.yaml

After encryption, the file will be updated, and all the values will be securely encrypted:

2  postgresqlUsername: ENC[AES256_GCM,data:D14/CcA3WjY=,iv...==,type:str]
3  postgresqlPassword: ENC[AES256_GCM,data:Wd7VEKSoqV...,type:str]
5  ...

By employing helm-secrets, the challenge of storing sensitive data as part of Helm charts is effectively resolved, ensuring the confidentiality of your critical information.

Reusable charts using template functions

Helm offers a rich set of over 60 functions that greatly simplify operations within templates. These functions, defined in the Go template language and Sprig template library, provide powerful capabilities for Helm users.

Consider the following example template file:

1apiVersion: v1
2kind: ConfigMap
4  name: {{ .Release.Name }}-configmap
6  environment: {{ .Values.environment | default "dev" | quote }}
7  region: {{ .Values.region | upper | quote }}

In this template, the environment value is given a default "dev" if not provided explicitly, thanks to the template function default. The region field, on the other hand, uses the upper function to convert the provided value into uppercase.

Another important function is required, which allows you to set a value as mandatory during template rendering. For example, suppose you need a name for your ConfigMap as shown below:

3  name: {{ required "Name is required" .Values.configName }}

If the configName entry is empty, the template rendering will fail, displaying the error message "Name is required." By utilizing template functions, you can enhance your Helm charts by improving templating, reducing code duplication, and validating values before deploying applications to Kubernetes.

Resource policies to opt out of resource deletion

In a typical Helm setup, when you install a Helm chart, multiple resources are created in your Kubernetes cluster. These resources can be upgraded by modifying values, adding or removing resources. When you no longer require the application, you can delete it, which removes all associated resources from the cluster.

However, there may be certain resources that should be retained in the cluster even after running the Helm uninstall command. For example, if you have deployed a database with a PersistentVolumeClaim, you may want to preserve the associated volumes even when deleting the database release.

To achieve this, you can utilize resource-policy annotations. These annotations allow you to specify the desired behavior for specific resources. In the case of preserving volumes, you would apply the appropriate resource-policy annotation to ensure that the PersistentVolumeClaim and its associated volumes are retained in the cluster even after the database release is deleted.

By employing resource-policy annotations, you can carefully manage the lifecycle of your resources and ensure that important data is not inadvertently lost during the uninstallation process. (Quotation marks are required)

1kind: Secret
3  annotations:
4    "helm.sh/resource-policy": keep

Be careful with generating random values

Helm provides functions that enable the generation of random data and cryptographic keys, among other things. These functions are useful and can be utilized in your templates. However, it's important to be mindful of their behavior during upgrades.

When a Helm upgrade is performed, the templates are re-executed. If a template generates data that is different from the previous run, it will trigger an update of the corresponding resource. This means that even if you use functions to generate random or dynamic data, such as cryptographic keys, be aware that changes in the generated data during an upgrade can trigger updates to the associated resources.

Keeping this in mind, it's important to carefully consider the usage of such functions and evaluate the impact they may have on your resources during upgrades.

Helm chart versioning strategies

When it comes to versioning Helm charts, there are several strategies you can adopt based on your specific requirements and workflow. Here are some commonly used approaches:

  1. Simple 1-1 Versioning: In this approach, the chart version is kept in sync with the application version it defines. You don't need to use the optional appVersion field. This strategy is recommended for beginners as it simplifies versioning and ensures the chart and application versions align. It can also be called as synced versions. This makes version bumping straightforward and allows easy tracking of the deployed application version. However, one downside is that it doesn't provide a separate tracking mechanism for chart changes.
  2. Chart versus Application Versioning: This advanced approach is suitable when changes frequently occur within the charts themselves, such as modifications in the templates. It enables separate tracking of chart changes from the application. It's important to establish a clear policy within your team on what constitutes a "chart change" since Helm does not enforce chart version changes. This approach provides flexibility, particularly for companies where different teams manage charts and application source code independently.

Effective versioning facilitates proper tracking, management, and coordination between the chart and application versions throughout your deployment lifecycle.

In conclusion, Helm is a powerful tool for managing application deployments on Kubernetes. By following best practices and understanding common misconceptions, Helm users can make the most out of this package manager. It is essential to adhere to naming conventions, understand the use of subcharts, leverage global values, organize charts effectively, secure secrets using plugins, and set resource policies.

Additionally, adopting appropriate versioning strategies ensures proper tracking and coordination between chart and application versions. By implementing these best practices, Helm users can streamline their deployments, improve collaboration, and effectively manage their applications on Kubernetes.

Useful resources:

Get started with Argonaut

Last post

Free AWS Credits: A Comprehensive Guide to Earning and Using Free AWS Credits

28 June 2023
Next post

Introducing CI Pipelines v2 With More Flexibility

20 June 2023