Helm (the Kubernetes package manager) 3.0.0 has been released
helm.sh
helm.sh
To new Kubernetes users, Helm appears to be the "Official" package manager, and the "right way to do it".
It's not.
Many helm charts are out of date, have subtle bugs, and are not actively maintained. Upstream projects often have their own way of customizing and rendering Manifests.
The biggest flaw in Helm is the decision to use text-templating for semantic data. This leads to ridiculous situations like having to specify the number of spaces to indent a block, so the output YAML can be parsed properly.
Promising alternatives are:
* Jsonnet [0]
See kube-prometheus [1] for a complex project that uses Jsonnet to accomplish things that would be much more difficult using pre-defined templating.
* Cue [2]
from the creator of BCL/GCL (Borg/Google Config Lang), which is what Jsonnet is essentially. He's written quite a bit about Cue and how he intends it to address the shortcomings of Jsonnet.
[0] https://jsonnet.org/articles/kubernetes.html [1] https://github.com/coreos/kube-prometheus [2] https://cuelang.org/docs/about/ [3]
First, there has been a lot of talk about how much work it is to onboard to Kubernetes. There have even been recent discussions in Kubernetes SIGs. In UX terms, Kubernetes has a high barrier to entry.
I realize that many people who use and know Kubernetes like it. We folks are a group that has gotten past the high barrier to entry. Most have not.
Second, Helm is a package manager. It's like apt, yum, homebrew, and others. It lets someone who knows how to run an application (ops business logic) on a platform (like debian or k8s) and package it up so someone else who doesn't know this can easily run an application. This is why so many use brew and apt to install something rather than install everything by hand.
Something like jsonnet doesn't solve for these situations.
I know some folks don't like text-templating. I'm not a big fan of go templating. But, templating is something that people are used to and generally comfortable with. This means it has a fairly low barrier to entry.
Notice, a lot of the reasons for why Helm does things is to reduce friction for a large audience. To reduce the barrier to entry.
Lots of Helm charts have bugs, but lots of PyPI/NPM/Maven packages have bugs as well.
Jsonnet, Cue, and operators are nice, but unless someone can create an ecosystem that is as valuable as the Helm ecosystem, I don't see Helm disappearing.
I ended up shelving it until I have time to take a proper course and dedicate the time to it. Docker compose was very easy to learn for me, with a few easy early "wins" and reasonably comprehensive and helpful documentation when I wanted to expand into new areas. For some reason, I really struggled grokking how to structure a k8 chart. Maybe I'll try again after a good night's sleep.
The major "wins" for using charts are usually around being able to use the same set of manifests with different values interpolated in. Which in turn, is really only valuable if you're supporting a large number of permutations that need to be kept in sync.
When you're doing simpler deployments then config files are great. It keeps the learning curve flat for new users. The problem is that as users get more experienced, they ramp up the complexity, then start trying to shoehorn more abstraction into a format where it doesn't fit.
The most visible example is the need for code reuse. Any sufficiently complex artifact is going to have a lot of similar sub-components. What you want is a macro or subroutine that translates simple parameters into common patterns. What you end up with is a lot of brittle copy-pasting.
Text templating is a kludge that usually works fine until it doesn't. At the end of the day everything ends up messily converging to Greenspun's Tenth Law.
In the future I predict we are moving towards a model where we have ways expressively define configuration (CUE) locally which we push to Kubernetes operators [0] which do the heavy lifting to deploy, monitor, and manage/upgrade a defined service that the operator is responsible for.
[0] https://kubernetes.io/docs/concepts/extend-kubernetes/operat...
My mind was blown when I saw this the first time. Let's hope that the developers are planning on supporting alternate templating schemes.
* Templates: deployment <Name>: ....
* List comprehensions: [ "-\(k)=\(v)" for k, v in arg ].
* Conditionals: targetPort: Port if port != Port
* Special templates: expose port <N>: .... What does 'expose' mean? Doesn't look like folded struct.
* Some form of comprehension/conditional composition: for k, spec in deployment if len(spec.expose.port) > 0. Can we nest two comprehensions? Can we zip? Can we reduce?
* Side note: What are the debug capabilities? One major usability issue with GCL circa 2010 was that debugging required sifting through MB [or was it GB?] of intermediate struct expansions.
* Side note: I wish they used Python f-string syntax: "-{k}={v}" instead of "-\(k)=\(v)".
[0] https://github.com/cuelang/cue/blob/e5d8d09b3ba2e4f48c84a3b5...
It supports Kubernetes, but also quite a lot more!
A recent example of Helm being a problem for me is their Elasticsearch chart. I tried to shutdown my data nodes to increase disk space on all of them, but I noticed after scaling down, the first instance was taking a _very_ long time to shutdown.
Turns out, there's a default lifecycle hook (pre-stop.sh) that drains the node and rebalances the shards to the other nodes as a pre-stop hook. (to me, this is a bad idea, the cluster operator should control draining and rebalancing the nodes.)
Guess what, there's no way to comment out the draining functionality since the shell script is mounted as a read-only ConfigMap. Annoyingly, the only solution was to disable re-balancing across the entire cluster, and then jumping on each node and run $ kill on the shell script for each node.
I've ran into strange defaults like that multiple times. I've ran into images randomly being changed, charts being upgraded but breaking your live deployment. Overall just a nightmare.
Kubernetes is actually quite understandable and consistent. Helm adds a layer of complexity that makes you scared to upgrade or change your cluster. If you stick to Kubernetes primitives like Deployments and StatefulSets, it's super easy to know what changes are going to occur in your cluster.
> In Helm 3, we now use a three-way strategic merge patch. Helm considers the old manifest, its live state, and the new manifest when generating a patch.
I will have to test this out, but honestly I think that any sort of "strategic" merge is probably the wrong approach to take when dealing with so called "idempotent" infrastructure.
Your manifest is idempotent but isn't applied instantly.
You can apply a manifest, and get into some broken state, how do you recover? What if you try to roll back and things get worse?
Doesn't seem that complicated, but maybe I'm missing some benefits of this strategy that others with more experience managing K8s resources have had.
Edit: Retroactively speaking you also don't need to leverage etcd to store n*x your K8s resources in a secrets file where n is the potential rollback number, it's all stored in a Git repository.
[1] https://kubernetes.io/docs/tasks/run-application/update-api-...
> The patch you did in the preceding exercise is called a strategic merge patch. Notice that the patch did not replace the containers list. Instead it added a new Container to the list. In other words, the list in the patch was merged with the existing list. This is not always what happens when you use a strategic merge patch on a list. In some cases, the list is replaced, not merged. [0]
This seems like a lot of cognitive overload. I understand there are some use cases for this but really, all I want is to have my K8s resources all tracked with a git commit reference and then that is what is deployed exactly.
[0] https://kubernetes.io/docs/tasks/run-application/update-api-...
I highly suggest re-reading the FAQ front-to-back on this subject. I spent a lot of time explaining the details on this subject. If you have any questions/concerns, we are always happy to discuss further on github.
https://helm.sh/docs/faq/#improved-upgrade-strategy-3-way-st...
I respect what someone has as an opinion. I just would like others to know where the opinion differs from the docs and tools out there. People can make their own choices.
Do you know how v3 prevents race conditions though? I assume there is some sort of locking mechanism via custom resources?
Tiller was not part of Helm v1. Tiller came in when Helm (which was developed outside of the Kubernetes project) was merged with deployment manager (which was part of Kubernetes). This produced Helm v2 which was part of Kubernetes. Helm grew large enough to spin off into it's own CNCF project.
Tiller was created early enough in the project that Secrets didn't exist at the time. This was long before RBAC or even the workloads API.
Tiller could have been remade as a custom controller which is how many things are created today. But, many people who share their apps work at organizations that don't let them install CRDs or use models like that. So, keeping the Helm footprint to a level that let's them and most others use it, if they choose, was a reason to remove Tiller. It also simplified the codebase a great deal.
We use helm, but for the life of me, there are some pretty poor design choices in there.
This is just an example and it's using go templates way of doing things.
So, more context...
Helm was designed to support more than one templating system. The problem was that the majority of people were ok with Go templates so no one contributed support for other systems.
Thus I'm sour on Helm, I'm rooting for Kustomize. [1]
[0] https://github.com/kubernetes/kubernetes/blob/master/cluster...
Oh, so now you're doing the obvious and simple thing? FFS...
Back then, Kubernetes had no concept of a ConfigMap. ReplicationControllers were all the hype (remember those?). The Kubernetes API was changing rapidly. When Helm 2 was being built, we needed an abstraction layer from the Kubernetes API to allow ourselves some room to guarantee backwards compatibility. Tiller was created as that abstraction layer. It provided us with a layer where we could control the input (via gRPC), the output (also via gRPC), and provide some backwards compatibility guarantees to users. We're pretty proud of the fact that Helm has maintained a strong commitment to backwards compatibility since 2.0.0.
Over time, Kubernetes' API layer has become more stable. Helm 3 is our opportunity to refactor out some of those protective layers we put in 4 years ago. Tiller being one of them.
Hope this helps provide some context.
Helm seems good enough as a package manager. But it forces me to use one particular text templating system. Why not allow a package to generate manifests with any system that it likes? This can be done reproducibly with a docker image in the k8s cluster (generate the manifests and send the manifests back to helm to apply them).
Deployment lifecycle management is complicated, and I can see why it is being coupled to templating values, but I don't think that must be the case.
It is great to see the 3.0 release just getting rid of Tiller, that's a useful step in this direction.
https://github.com/helm/helm/issues/5084
Does beg the question what have they been doing all this time. V3 has been a long time in the making.
To provide some perspective, over 80,000 lines of code was changed between 2.16.1 and 3.0.0, including test infrastructure, the architecture, documentation...
We started development on Helm 3 last year in March, shortly after the first Helm Summit in Portland. A complete redesign of the architecture in 20 months time seems pretty par for the course for a project of this size.
However, it fails when the reality of running a service in production hits and you need to dive into changing a Chart template, requiring knowledge of not just the Kube API but also more often than not ugly template-fu to get the changes that you want reflected.
I really just recommend using raw K8s resource files for almost everything unless you are managing hundreds of similar releases.
https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-a...
If you’re using Kube you need to understand Kube. Conveniences are great to accelerate common tasks but as you say at some point ya gotta get into the guts of it and tweak things.
A package manager lets someone who has knowledge of how to run an application on a platform (e.g., postgresql on debian) package it up in a way that others who don't have this knowledge can run an application without needing to learn it.
That's why I can use `apt install` regularly without needing to know the business logic of running all those apps on my system.
Package managers let you compartmentalize and automate expertise.
I've lost track of how many times helm has misrepresented the result of upgrade operations, even returning success when it actually failed, and what should be routine upgrades often break in ways that require detailed knowledge of both kubernetes and helm to recover from.
Yes, conflicts and failures do sometimes happen with package managers, but with helm we've seen it happen with nearly every Chart at some point or another, from the simplest single-resource pipelines to widely used community projects.
Helm 3 will help, but it's still built around the same messy string-templating system that ensures Charts are fragile and difficult to understand.
what is the competing tech?
In fact, helm has moved closer ideologically in this new release to what Kustomize is.