Sometimes the limitations of kustomize annoy me, but we find ways to live with them
But, if it helps, my mental model of Kustomize is "it's a sequence of JSON Patch [1] operations"[2] which makes it absolutely stellar for mutating someone else's helm chart[3] (or yaml) since you can target anything for updating to your needs
My secondary complaint is that even JetBrains don't have good support for it, which makes working with them extra hard mode
1: https://www.rfc-editor.org/rfc/rfc6902.html
2: it's a very "functional programming language" mental model https://kubectl.docs.kubernetes.io/references/kustomize/kust...
3: https://kubectl.docs.kubernetes.io/references/kustomize/buil...
We do package our own helm charts, not in the least because we sign contracts with our customers that we will help them run the software we're selling them. So we use package docker and helm artifacts that we sell in addition to running locally.
So we write some charts that don't use most helm features. The one useful thing about Helm that I don't want to live without is the packaging story. We seem to be the only people in the ecosystem that "burn in" the Docker image sha into the Helm chart we package, and set our v1.2.3 version only on the chart. This means we don't have to consider a version matrix between our config and application. Instead we just change the code and config in the same git sha and it just works.
Replacing with hash is a neat idea, might start doing that too.
Yet somehow, all we have is YAML templating?
1. having the ability to create a release artefact helm chart for a version, and store that artefact easily in OCI repositories. 2. being able to uninstall and install a chart and not have to worry about extra state. Generally in Kustomize people just keep applying the yaml and you end up in a state where there’s more deployed than there is in the kustomize config
- Makes it possible to go from zero to fully running k8s integrated components in 5 seconds by just running 'helm install --repo https://example.com/charts/ mynginx nginx' (very useful: https://artifacthub.io/)
- Gives the ability to transactionally apply k8s configs, and un-apply them if there is a failure along the way (atomic rollbacks)
- Stores copies/versions/etc of each installation in the server so you have metadata for troubleshooting/operations/etc without having to keep it in some external system in a custom way.
- Allows a user who doesn't know anything about K8s to provide some simple variables to customize the installation of a bunch of K8s resources.
- Is composeable, has templates, etc.
So basically Helm has a lot of features, while Kustomize has... one. Very different purposes I think. You can also use both at the same time.
Personally I think Helm's atomic deployment feature is well worth it. I also love how easy it is to install charts. It feels a bit like magic.
Realistically, a plain helm install without any values rarely if ever gives you the deployment you need, so you have to study the chart anyways.
> rollback on failure
This is hardly unique to helm.
> history metadata without (...) some external system
In 2025 you should probably be using gitops anyways, in which case the git repo is your history.
works for me most of the time
> This is hardly unique to helm.
So what? The guy was asking what is nice about Helm vs Kustomize. Does Kustomize have rollbacks?
> In 2025 you should probably be using gitops
Gitops is literally just "hey I have some configs in Git and I run some command based on a checkout", i.e. infrastructure as code in a git repo. Gitops does not track live server metadata and deployment history. I don't get why people over-inflate this idea.
Please check https://opengitops.dev/
I believe(!) that the "rollback" that helm attempts to put back all the mutated objects, which it can - in theory - do because it maintains the previous state in the Secret objects that contain the rendered(?) and the values for the prior revision
try:
for obj in manifest_objects:
kubectl_apply(obj)
revisions.push(manifest_objects)
except:
old_revision = revisions.pop()
for obj in old_revision:
kubectl_apply(obj)
type dealVery very little else seems to bring this basic sense to Kubernetes. Metacontroller kind of could do that. Crossplane's whole business is this, but it's been infra-specialized: but the Crossplane v2.0 release is trying to be much more generally useful. https://docs.crossplane.io/v2.0-preview/whats-new/ . Would love other examples of what does composition in Kube.
Kustomize had the issue that it would leave objects dangling in the cluster and you had to manually clean them up of you removed them from your kustomization file.
In true GitOps, I think it's should be default on.
There is another category of users who want a way to mange multiple vendor offerings in a consistent manner into their clusters. If they're all packaged with Helm, the user can have standard process and tooling to do that. It's done for K8s apps what containers did for executables.
Is it great? No, see the grief and pain in sibling threads. Are there alternatives? Sure. But Helm is sort of a standard at this point, warts and all.
I work for a vendor that sells to the second category usually, my chart has some 45 images with some intricate hooks for install and upgrade, subcharts, multiple namespaces, etc. You'd be hard pressed to repackage our stuff for every release we give you.
Ironically (in the context of this submission) Bitnami has a "--schema" option to their README generator, which is why so many of their charts ship with .schema.json files: https://github.com/bitnami/readme-generator-for-helm/tree/2....
There are likely other "give me a schema for this example JSON/YAML file" but almost certainly wouldn't come with the nice {"description":""} blocks, nor the {"required":false} that an annotated .yaml can offer
While digging up that link, I also spotted the tag line in their GitHub org which is hilarious https://github.com/bitnami#:~:text=trusted%20by%20ops
Another way that JetBrains tooling shines, because it automatically turns on JSON Schema support for the chart when it has one, no extra # schema=file://... dumbness required
I was talking about the go templates that make up the actual chart. Ensuring they only use string values for annotations for example seems like a hard problem to solve. Even just showing the type and description from the schema seems nontrivial.
---
As for the "only string values for annotations," I think you mean patternProperties:
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"annotations": {
"type": "object",
"description": "this is the description of the annotations key itself",
"additionalProperties": false,
"patternProperties": {
"^[a-z][a-z0-9./]+$": {
"type": "string",
"description": "holds the value of the annotation"
}
}
}
}
}
and if I put the following, then the 123 gets flagged as a schema violation annotations:
alpha: 123
as does annotations:
_: xxx
0xcafebabe: denied
---If you mean schema checking on the output, that is checked by the OpenAPI built into Kubernetes itself, so yes, doing something silly in golang templates will not, by itself, check the result - that's one of the major limitations of Helm's moronic choice of using a text templating language for a structured file format
I might use Helm charts for initial deploys of operators, but that's about it.
Kustomize is, IMO, a better approach if you need to dynamically modify the YAML of your resources and tools like ArgoCD support it.
You can read a comparison with Helm here: https://www.ohayocorp.com/anemos/docs/comparison/helm
P.S. I am the author of the tool.