Benjamin Kušen
January 13, 2024

Helm: Best Practices

Discover essential Helm best practices for Kubernetes deployments in this comprehensive guide. Streamline your helm charts today

Helm functions as a package manager for Kubernetes applications, offering methods to create templates and organize Kubernetes manifests as versioned packages. These suggestions are derived from books, articles, and professional experience.

Follow Helm Conventions

Code conventions are foundational guidelines that allow the creation of a consistent codebase throughout an organization. Adherence to these conventions not only enhances code uniformity but also its quality. The Helm documentation offers some General Conventions and Best Practices.

These conventions cover areas such as naming conventions, templates' structure and organization, dependencies, labels and annotations, Pods and PodTemplates, custom resource definitions, and role-based access control. The 'Developer's Guide to Writing a Good Helm Chart' is a recommended read.

Use Helm Create Command

For those new to Kubernetes, a common practice is to take some manifests from the Kubernetes documentation and manually construct their Helm chart from the very beginning. However, this method is susceptible to errors and is quite tedious.

Instead, using the command helm create <my-chart> will generate all the typical Kubernetes manifests (deployment.yaml, hpa.yaml, ingress.yaml, service.yaml, and serviceaccount.yaml) as well as aid templates to help bypass resource naming restrictions and labels/annotations. You just have to modify the values.yaml file to deploy your Docker image.

Explore Public Charts

Arguably, the most notable advantage of Helm lies in its large community. When you find yourself stumped, it can be helpful to traverse through some public charts for ideas or smart answers to frequent tasks. To search for charts, you can use the in-built helm search command:

<pre class="codeWrap"><code>helm search hub</code></pre>

The said command will look for charts in the Artifact Hub or in your own hub instance. Alternatively, the helm search repo command searches repositories for a keyword in charts.

Do Not Put Everything in One Chart

If multiple services need deployment, it's more efficient to create a separate chart for each service. This practice simplifies the management of your deployments and upgrades and also facilitates troubleshooting in case of any issues. It's also recommended to create a shared chart for communal resources, like config maps and secrets. By doing so, you can repurpose these resources across all of your charts, eliminating the need for duplication.

Use Subcharts to Reuse Code

It is advisable to create or utilize separate charts for independent applications, and then add them to the main or parent charts. Subcharts are deployed concurrently with the primary chart. The values for subcharts can be included in the same values.yaml file as the main chart.

The recommended folder structure should follow this order:

<pre class="codeWrap"><code>├── Chart.yaml
├── charts
|  ├── backend
|  |  ├── Chart.yaml
|  |  ├── templates
|  |  |  ├── deployment.yaml
|  |  |  ├── secrets.yaml
|  |  |  ├── ...*.yaml
|  |  |  └── service.yaml
|  |  └── values.yaml
|  ├── database
|  └── frontend
├── templates
└── values.yaml
</code></pre>

Have a Git Repository

Maintaining a Git repository can offer various perks solely through its usage, including effortless rollbacks or the facility to monitor changes. By circulating your code in a Git repository, you can collaboratively work with your team members easily. Additionally, the preservation of the source code in a Git repository holds significant importance and is regarded as one of the top-notch practices for CI/CD.

Utilizing a revision/version control system is also vital to oversee changes, differentiate variances, and manage an environment that simplifies tracking your chart releases.

Have a Chart Repository

A chart repository can be defined as an HTTP server that accommodates an index.yaml file and, if needed, some packaged charts. That is to say, a chart repository is merely a location where packaged charts can be stored and shared. By disseminating your Helm charts in a central repository, you can seamlessly collaborate with other team members and share your projects with the broader Helm community. Upon the creation of your Helm chart repository, you can push your charts to it by employing the helm push command.

Test Templates and Charts

Helm charts comprise multiple resources destined for deployment to the cluster. Ensuring that all resources are in place in the cluster with appropriate values is vital. It's advisable to write tests for your charts and execute them post-installation. For instance, the helm test &lt;release-name&gt; command can be utilized to conduct tests. Alternatively, helm unittest can serve as a BDD-structured unit testing framework for Helm charts in the format of a Helm plugin.

Generate documentation for charts

As with every software component, documentation plays a critical role in its usability. Inside a Helm chart, one can utilize inline annotations, the NOTES.txt, along with the README document. The most straightforward route to creating and maintaining documentation is by applying a Golang package named helm-docs.

Utilizing helm-docs allows you to generate a README that incorporates tables of values, versions, and descriptions sourced from values.yaml and Chart.yaml. helm-docs can be incorporated into pre-commit in conjunction with linting.

Sign and Verify Charts

Sign your charts using the helm package –sign and authenticate them with helm install --verify. The affirmation of software component integrity is the chief routine for securing the software supply chain. Integrity is confirmed by contrasting a chart with a provenance record. Helm leverages a PGP-based digital signature to formulate provenance records stowed in provenance files (.prov), which are stored adjacent to a packaged chart.

Scan Charts Regularly

The CIS Kubernetes Benchmarks points out several ways in which an object deployed to Kubernetes might accrue too many permissions if a certain configuration is missing from the Kubernetes YAML defining the object. These benchmarks also advise against configuration options that may expose a larger attack surface.

Helm chart misconfigurations will resemble those seen with a Kubernetes YAML manifest misconfiguration. For automated vulnerability assessments of Helm Charts, integration with a CI pipeline is possible. Tools like Trivy or Checkov can be employed to uncover vulnerabilities/misconfigurations in Kubernetes YAML files.

Keep the Deployments Idempotent

An operation is regarded as idempotent when it can undergo multiple applications without altering the outcome after its initial execution. You can maintain deployments' idempotency by employing the helm upgrade --install command as an alternative to using install and upgrade separately. This command will install the charts if they hadn't been installed prior. If they are already installed, it opts for upgrading them.

Moreover, with the --atomic flag, you could revert modifications in consequence of a failed procedure during a helm upgrade. This precaution ensures that Helm releases do not remain in a failed state.

Rollbacks with Version Control

There exist situations where the testing team might encounter problems that were not identified in the former software release. A likely cause could be an unforeseen consequence of a fix that was introduced in the software release currently under scrutiny. In such instances, the developer responsible for that fix should have the capability to roll back his changes.

This ensures that the release isn't impeded and offers him additional time to reevaluate his implementation. Without a version control system, such a smooth rollback is infeasible. The rollback isn't confined solely to source code - it could extend to documents, presentations, flow diagrams, and so forth.

Automatically Roll Deployments

It's typical to mount ConfigMaps or Secrets to containers. Despite the deployments and container images undergoing changes with new releases, the ConfigMaps or Secrets don't alter as frequently. The sha256sum function can be deployed to guarantee that a deployment's annotation section gets updated if there's a modification to another file:

<pre class="codeWrap"><code>kind: Deployment
spec:
 template:
   metadata:
     annotations:
       checksum/config: &#123;&#123; include (print $.Template.BasePath "/configmap.yaml") . &#124; sha256sum &#125;&#125;
</code></pre>

Use Template Functions

Helm features an array of template functions that you can utilize in templates. These functions are formulated in the Go template language and Sprig template library. Such template functions are incredibly valuable when constructing Helm charts. They can enhance templating, diminish code duplication, and can also be used to validate values prior to deploying your applications to Kubernetes. Review the following example applying the upper function:

<pre class="codeWrap"><code>kind: ConfigMap
data:
 regions: {{ upper .Values.regions }}
</code></pre>

Use Lint, Template, and Debug Commands

The use of a linter helps evade common errors and establishes best practice norms for engineers to adopt in an automated manner. Execute the helm lint command to verify that your chart aligns with these best practices. Alternatively, KubeLinter and Kubeval can be employed to parse Kubernetes YAML files and Helm charts. These are frequently used in local development workflows and are also integrated into CI pipelines.

The helm template command will render chart templates and display output. For server-side template rendering and then returning the resultant manifest file, commands like helm install --dry-run --debug or helm template --debug serve this purpose. To observe what templates are installed on the server, the helm get manifest command is effective. Similarly, the helm get values command retrieves the release values deployed to the cluster.

Use Small-Sized Images

If your image is founded on a comprehensive OS distribution such as Ubuntu or Centos, the image will incorporate a myriad of tools pre-packaged. Although this increases the image size, most of these tools are not required in your application images. Conversely, if you opt for minor images with streamlined OS distributions, which exclusively bundle the essential system, you would require less storage space, reduce the attack surface, and generate more secure images.

The recommended practice here would be to choose an image with a specific version based on a leaner OS distribution like Alpine.

Avoid Privileged Containers

Ensuring a container executes only a strictly limited set of actions is critical for production deployments. This is achieved via the usage of non-root containers, which are run by a user separate from the root. You can confine the capabilities of the container to the bare minimum set needed through the securityContext.capabilities.drop option. Thus, should your container be violated, an attacker would have only a limited spectrum of potential actions.

Limit Container Resources

Inherently, a container does not have resource constraints and can utilize as much of a designated resource as is permitted by the host's kernel scheduler. It's advisable to restrict the memory and CPU usage of your containers, particularly if you're operating multiple containers.

Further, when a container gets compromised, attackers might attempt to exploit the underlying host resources to carry out malicious activities. By setting resource requests and limits for Pods and containers, one can mitigate the effects of violations on resource-intensive containers.

Include Health/Liveness Checks

Health checks serve as a straightforward method to inform the system if an instance of your app is functioning or not functioning. Numerous applications, after prolonged run times, eventually deteriorate into irrecoverable states unless restarted. By default, Kubernetes initiates traffic flow to a pod as soon as all the contained pods boot up, and it reboots containers in the event of a crash.

Although this could suffice when you're in the early stages, establishing custom health checks can significantly enhance the robustness of your deployments.

Include Logging and Monitoring Tools

It's crucial to have accurate monitoring of our deployments for early detection of possible issues. It's equally vital to obtain metrics of application usage, cost, and resource consumption. To gather this data, one would typically deploy logging stacks such as ELK (ElasticSearch, Logstash, and Kibana) alongside monitoring tools like Prometheus.

While writing your chart, ensure that your deployment is compatible with these tools. To assure this, ascertain that all the containers log to stdout/stderr and Prometheus exporters are incorporated.

Use Labels to Find Resources

Labels hold significant importance for Kubernetes' internal operations and the routine tasks of Kubernetes operators. Nearly all resources within Kubernetes provide labels for different aims, including grouping, resource allocation, load balancing, or scheduling. A solitary Helm command permits the installation of multiple resources. However, it's essential to identify the source of these resources. Labels facilitate the swift location of your resources created by Helm releases.

Separate Values by Environments

Default values are denoted for the majority of settings in a values.yaml file, and these values are transferred into the chart. You can manage the values YAML files in the root directory, specifically values-[env].yaml. For instance, values-dev.yaml and values-prod.yaml for the dev and prod environments, respectively. Each value file is utilized based on the environment for deployment. A values file is inputted into helm install or helm upgrade with the -f flag.

Store Secrets Encrypted

Sensitive information, like keys or passwords, is preserved as secrets within Kubernetes. Base64 is an encoding algorithm, not a cryptographic one, and despite its title, Kubernetes secrets are not hidden. Some individuals opt to store encrypted secrets adjacent to the code, while others favor an alternative location. Several noteworthy options consist of the helm-secrets plugin, Hashicorp Vault, Sealed Secrets, and Mozilla's SOPS, among others.

Take Advantage of Helm Hooks

Frequently, developers of a Helm chart may wish to conduct some auxiliary operations before installing or upgrading the main service that is essential for the appropriate functioning of the main service. Helm hooks are basic Kubernetes manifest templates identified by an annotation, the value of which dictates when the hook should be rendered. Helm hooks grant you a chance to execute operations at strategic junctures in a release lifecycle.

Facing Challenges in Cloud, DevOps, or Security?
Let’s tackle them together!

get free consultation sessions

In case you prefer e-mail first:

Thank you! Your message has been received!
We will contact you shortly.
Oops! Something went wrong while submitting the form.
By clicking “Accept”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Privacy Policy for more information. If you wish to disable storing cookies, click here.