How To Convert Kubernetes YAML to Helm

And Why Helm is Actually a Light-Weight Approach to Kubernetes deployment

Recently I saw several comments on various forums suggesting that Helm is a heavy-weight approach. Instead, people were resorting to using plain YAML applied via Kubectl and trying to use sed for modifications.

In some cases they were going towards Kustomize even though Helm could be a better tool for the use-case. The reason they were looking at Kustomize was due to common perception that Kustomize is a much lighter tool. I believe this is a fallacy.

Here I will try to explain why Helm is actually a very light-weight tool and describe most simple transition from a set of Kubernetes YAML towards creation of a Helm chart.

I will use our open source Rebom project as a training ground.

1. Helm 3 is Just an Executable

First, there are some misconceptions around what Helm is. Previous version of Helm – Helm v2 – had client and server components (server component was called “Tiller”).

Modern version of Helm – Helm v3 – has only a client executable. In a sense that is very similar to the Kubectl utility. The server side is now replaced with Kubernetes metadata – which is what makes it extremely lightweight.

Also, a number of Helm debug commands may be performed without connectivity to a Kubernetes cluster. That is very useful for local development and debugging.

With all that said, I will proceed with actual end-to-end example of creating a Helm chart out of a set of YAML files.

Installation of Helm can be done as easily as downloading proper Helm executable for your system, unpacking and making it available on the system path.

Once installed, you should be able to just run

helm

and get its CLI help instructions. If it runs correctly – this is already enough for any local commands. To point Helm to a Kubernetes cluster, make sure that your KUBECONFIG environment variable is set properly.

I hope everything looks light-weight so far.

2. Deploying plain Kubernetes YAML files via Kubectl

Look at my sample repository here – https://github.com/taleodor/rebom-helmify – I start with a set of plain Kubernetes YAML files that are located inside plain-kubernetes-yaml directory. Fork and clone this repository if you want to try it out on your own.

These sample YAML files can be applied simply with:

kubectl apply -f plain-kubernetes-yaml/

This would spin a sample Rebom application in the default namespace.

This is great, why do we even need a helm chart? Simplest explanation – try now to uninstall the thing we just deployed. You’ll see that it requires 8 (!) commands:

kubectl delete deployment rebom-frontend
kubectl delete deployment rebom-backend
kubectl delete statefulset postgres
kubectl delete ingress rebom-ingress
kubectl delete service rebom-backend-service
kubectl delete service rebom-frontend-service
kubectl delete service postgres
kubectl delete secret pgpassword

This still leaves PVC’s behind – which is fine, we want to keep it this way.

To figure out those commands you need to be well aware what is inside plain YAML definitions and what resources they create.

Other problems include requirement to edit YAML definitions in different files even for routine changes – such as image updates or various host names per environments. Wouldn’t it be nice if we had a dedicated place which would outline all configuration and all parameters?

A Helm chart would solve all that.

3. Building a Helm chart out of existing Kubectl YAML files

I hope I gave enough reasons above why we would like to move to something better than a simple set of plain Kubernetes YAML files. Let’s now build a Helm chart on top of our existing plain YAML definitions.

Given that we already have plain-kubernetes-yaml directory, we will now create a Helm chart in few simple steps. For this, I will use helmify branch in my repository – you can work in your fork if you would like to mimic.

Let’s start:

a. From the root of the repository run the following Helm command to create a chart:

helm create rebom

This would create a simple outline for the Helm chart, including sample Chart.yaml and template files. Chart.yaml is where our main chart metadata is located, and template files are essentially templated Kubernetes YAML definitions.

b. Delete all sample files that we won’t be using (which is essentially everything but .helmignore, Chart.yaml and _helpers.tpl function template helper:

rm rebom/templates/NOTES.txt
rm rebom/templates/*.yaml
rm -rf rebom/templates/tests
rm rebom/values.yaml

c. Copy plain yaml files into the templates section of the helm chart

cp plain-kubernetes-yaml/* rebom/templates/

This is actually it. We now have our Helm chart ready. You may see results of the above commands on my side in this commit.

We can now deploy it (assuming you have KUBECONFIG environment variable configured properly):

helm upgrade --install rebom rebom/

And here is the uninstall part:

helm uninstall rebom

Compare this to the plain YAML way! Note, it still leaves PVC’s behind – which is again a good thing so we don’t accidentally lose data.

4. Conventionalizing Helm Chart – Standard Labels

Now, let us put standard conventions for Helm – which include some standard labels and annotations.

Remember that we kept auto-generated file _helpers.tpl in the templates/ directory. We will use it now. Particularly, we are interested in auto-generated templates “rebom.labels” and “rebom.selectorLabels”.

Now, for each top level metadata labels, we would set rebom.labels template and for all selector labels, we would set rebom.selectorLabels accordingly. You can see the full change in this commit.

Note that we use nindent notation here to specify the number of whitespaces each line must be padded with. See official documentation here for more details.

5. Parametrizing Names and Namespace

Next, notice that we currently have default namespace hard-coded in our YAML files. This is very inconvenient for the case where we want to deploy our application to a different namespace.

Similarly, all resource names are hard-coded too. This is not a big deal for this application, but consider a case where this may overlap with a different application for the same namespace. Again, we would like to do more work to prevent possible name collisions.

For the namespace issue, we are going to use Helm’s standard {{ .Release.Namespace }} notation – this will make resource namespace resolve to the namespace to which Helm chart is installed to (using -n or --namespace flag).

Similarly, we will prefix all resource names with {{ .Release.Name }} Helm’s notation which resolves to the name we are choosing for the Helm release in the install command.

So that for example, if we install the chart as:

helm upgrade --install rebom -n rebomns \
  --create-namespace rebom/

then .Release.Name would be resolved to rebom and .Release.Namespace would be resolved to rebomns.

We are also modifying various places where names may be referenced accordingly. See results in this commit on my side.

6. Parametrizing options per-service. Introducing values.yaml file

Finally, each service we use may have some parameters that are dependent on environment. Base parametrization file for a Helm chart that usually holds all available parameters with their default values is called values.yaml file.

Then, for each environment we may create a separate values file and supply it to the cli command.

First of all, we parametrize container images used for each service. We would add a basic values.yaml file for that purpose. Refer to this commit to see how I did it.

Next, we extend our values.yaml to include additional parameters, as you can see in my next commit.

As mentioned above, we may now introduce separate values files that would be specific per target environments. Such files may be added to the Helm’s install or upgrade command using the -f flag. In example, refer to the original Rebom repository which contains such file for the demo environment – called values-rebomdemo.yaml – and it can be used with the following command on install or upgrade:

helm upgrade --install rebom -n rebomns \
  -f values-rebomdemo.yaml \
  --create-namespace rebom/

Note, that you can nest several values files in such manner. Also, important to note that such extra files are all additive – with the latest added values file taking precedence. If any key is not overwritten relative to values.yaml – the value specified in values.yaml will be used.

With that we can consider our Helm chart complete. You may refer to the original Rebom repository for its latest iterations.

7. Going back from Helm to YAML

One of the most powerful tools in Helm is ability to render back parametrized Helm chart into plain YAML. This may be achieved using helm template command.

For example,

helm template -f values-rebomdemo.yaml rebom/

would produce YAML of our chart as it would look on the demo environment.

8. Merging Helm chart values

Helm has hidden functionality to merge different values file into a single file with all values combined, including resolution of all overrides. We have exposed this functionality in the reliza-cli tool, and you can follow documentation here to take advantage of this functionality.

9. Conclusion

With all the steps above, we now have a fully functional Helm chart that can be further updated using various functions as described in the Helm documentation.

I hope you can appreciate that the Helm tool is really easy to use and lightweight and deserves to become a standard how we package and deploy applications on Kubernetes.

1 comment

Leave a comment

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