Helm Best Practices (Part 1)

As you understand Helm’s workflow and develop your charts, you’ll notice that we usually have multiple paths to get things done.

If we have 5 options for solutions, then it is difficult for a beginner to understand which one is better.

Here I tried to create a list of general guidelines and recommendations to get an idea of ​​the best ways to work with helm charts.

There will be 7 topics in 3 posts, and mostly it is in the Helm documentation at the link https://helm.sh/docs/chart_best_practices/


Let’s start with the chart names.

Their names must contain only lowercase letters and numbers. Also, if the title should be multiple words, separate them with hyphens, as you see here.

Fine

nginx
wordpress
wordpress-on-nginx

Not good

Nginx
Wordpress
wordpressOnNginx
wordpress_on_nginx

As for chart version numbers, Helm recommends the SemVer2 notation or Semantic Versioning 2.0.0.

You may not be familiar with this name, then you have already met with it many times.

In short, version numbers are of the form MAJOR.MINOR.PATCH.

The first number is the major version number, the second is the minor version, and the third is the patch number.

Let’s say yesterday you created a brand new application and assigned version `0.1.0` to it.

Today you found a security bug and fixed it. Along with the application, its version will also change, it will become `0.1.1`.

Later you find another mistake and fix it. The version will change again and become `0.1.2`.

Ok, then you make small changes to your application, for example, change the function, removing unnecessary loops, so that it starts consuming 5% less memory. This may become version `0.2.0`.

Note that when you update a minor version number, the patch number is reset to 0.

Finally, you do a major refactoring, making a huge update to your application, adding a lot of new features and changing some of the existing ones. Since the changed functions are heavily reworked, they may not be fully compatible with the old ones.

In this case, the major version will change and become `1.0.0`.

This approach to versioning holds true in designing your own helm charts as well.


Now let’s talk about the `values.yaml` file.

All variable names in the `values.yaml` file must start with lowercase letters.

Also dashes and underscores are not supported.

Very often a variable must contain several words to make it clear what is being said.

Use case `camelCase` when the first word starts with a lowercase letter and all subsequent words start with a capital letter.

Here I have shown both right and wrong.

Fine

replicaCount:   3
wordpressSkipInstall:   false
wordpressUsername:   user

Not good

ReplicaCount:   3
wordpress_skip_install:   false
wordpress-username:   user

At the same time, the first two incorrect lines, those with the first capital letter and underscores will still be accepted, but with a dash – not at all.

As for the variable structure itself, we have flat and nested formats.

Nested

image: 
    repository:   nginx
    pullPolicy:   IfNotPresent
    tag:   "1.16.0"

Flat

imageRepository:   nginx
imagePullPolicy:   IfNotPresent
imageTag:   "1.16.0"

As you can see, there is a logical grouping above, namely `image` includes the concepts of an image repository, an image tag, and a download policy. Therefore, these fields are children of the image field.

We can recycle this into a flat format, as you can see below.

Ok, if possible, we should prefer the flat format.

But if we have several related variables that can logically be nested inside each other, and we are sure that at least one of them will always be used, we group them with a nested method.

If the variables are not related to each other, or are related, but optional, say, the values ​​have some default values, and redefinition happens in very rare cases, then it is better to do it in flat mode.

Now let’s talk about the field values ​​themselves.

Here is a boolean parameter `enable: false` we will further check in the template using the if or with block.

values.yaml

enable:   "false"

startTS:   1670843898

templates/timer.yaml

{{- with .Values.enable }}

startTimeStamp:  {{  $.Values.startTS  }}

{{- end  }}

release-name/templates/timer.yaml

…
startTimeStamp:   1.670843898e+09
…

Below is the rendering result of the template.

So, the value of `enable` will be false if it is specified like this:
— `false` in small letters,
— `FALSE` large,
— `False` with a capital
– and in the value 0.

If you set `enable: FalSe` with mixed case characters as you see here, then the `with` loop over `.Values.enable` will successfully output the contents of the block.

As for quotes in values, `enable: false` and `enable: “false”` will assign different types to the variable.

In the first case, a logical Boolean type is assigned. In the second case, a string value is assigned, which will be understood as true.

Always enclose string values ​​between double quote characters if you are not sure about them.

With integers, too, there are features.

Let’s say we have a number of epoch timestamps in the `startTS` field.

When the template file is parsed, its value will be converted to exponential notation. The result is a fractional number with a degree.

When working with large numbers, you will definitely encounter this problem.

Just define the number as a string by adding double quotes, as you can see here.

After that, in your template files, when you need to use this variable, prefix it with a type conversion function int for large numbers or int64 for very large numbers.

values.yaml

enable:   "false"

startTS:   "1670843898"

templates/timer.yaml

{{- with .Values.enable }}

startTimeStamp:  {{  int  $.Values.startTS  }}

{{- end  }}

release-name/templates/timer.yaml

…
startTimeStamp:   1670843898
…

Thus the string `167 etc.` will be converted to the number 167…etc rather than its exponent.

Also, in modern versions, you can just set to int without converting the value to a string, this will remove the exponent.

Ok, it’s good practice to document the `values.yaml` files.

When the user opens the values ​​file, all they get is a long list of variables.

Of course, it will be very difficult for him to understand what each of them is used for. This is why we should always document each field by adding a comment above it. A comment starts with a pound sign. For example, as you see here.

values.yaml

…

## replicaCount Number of NGINX replicas to deploy
##
replicaCount:   1
## updateStrategy.type NGINX deployment strategy type
## updateStrategy.rollingUpdate NGINX deployment rolling update config
## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
##
updateStrategy:
    type:   RollingUpdate
    rollingUpdate:   {}
## podLabels Additional labels for NGINX pods
## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
##

…

Notice how we start the commentary. We write from the actual name of the variable. This is the recommended approach as it both simplifies searching and especially helps auto-documentation tools match our notes with the parameters they describe.

Before we move on to the templates, we are left with the LICENSE and README.md files.

The license is a plain text file, in which we write on what conditions we deliver the chart. There may also be licenses for the application that puts the chart. Keep in mind that your chart may contain sub-charts that contain logic that the creators can impose restrictions on. It’s better to tell users about it here.

A README file is a Markdown instruction and usually contains:

— description of the application in the chart
– commands how to install the chart
— prerequisites for launching the chart
– descriptions of the values.yaml file parameters and default values
— features of installation, configuration and debugging of the chart

This information is used by the automation of the repositories when it displays data about the charts, and the `helm show readme` command also works with it.

Ok, that’s all in this post, we’ll continue in the next one.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *