Tools like Helm solve this problem.
Helm, like any abstraction, has costs and values. For example, it's very valuable to be able to encode something like "my app consists of a frontend and a backend that run in the same Pod and must each use the same version of the code":
apiVersion: v1
type: Pod
metadata:
name: foo
spec:
containers:
- name: frontend
image: my.registry.io/foo-frontend:{{ .tag }}
- name: backend
image: my.registry.io/foo-backend:{{ .tag }}
Now your frontend and backend containers can't get out of sync, and it saves someone from having to manually ensure that they are sync'd. There's no way to do it wrong! You supply {{ tag }} and it remembers the constraint that you required.The problem with this abstraction is that there's no escape hatch. If you wanted to run different versions of foo-frontend and foo-backend, there is no way to say "but no, really, this time I'm violating the rules for a good reason". You've reduced the features available... the only way forward is to start over with nothing.
The result of this is that every individual Helm chart has to account for every possibility that the manifests could possibly encode, and invent their own programming language that is identical in expressiveness to the underlying manifests. And they do! Differently every time! For example, if I wanted to allow people to override the container images, I'd have to make my template look like:
containers:
- name: frontend
{{ if .tag }}
image: my.registry.io/foo-frontned:{{ .tag }}
{{ else }}
image: {{ .frontend_image }}
{{ end }}
- ...
Now it's possible, but not in a way that anyone could search for on the Internet. You will have to read the code or hope I wrote documentation for my ad-hoc Kubernetes extension.I think we can all agree that didn't save anyone any time or effort.
This example conveniently flows into my other complaint with Helm. The "yaml files" that declare templates aren't actually valid YAML. You can't use something like `prettier` to autoformat them. You can't use the YAML language server to provide code advice as you type. You can't use `kubeval` to validate them. You are throwing all of that away to Build Your Own Thing. It is actually very insidious and for that reason I consider Helm to be more harmful than helpful. It isn't an abstraction, it's just a macro that might be good for one person the instant they happened to type something in.
The other problem is that Helm charts have no upgrade path. They are only designed for "please explode this project into my cluster, I promise to clean it up In The Future". It never gets cleaned up and brings a little piece of un-updated Windows 95 nostalgia right into your cluster.
Helm is actively harmful. And people love it, because it saves them a tiny bit of time one day at the cost of a lot of time in the future.
I see putting your example of two, unrelated, containers in the same pod as the same binary problem I mentioned earlier. I get your point, but it's a scenario one must wedge themselves into by making other poor choices. Why must the frontend and backend be the exact same version? The most obvious possible reason could be that the API used between them isn't versioned. Or maybe there's not even an API!
> You will have to read the code or hope I wrote documentation for my ad-hoc Kubernetes extension.
No, helm's approach to inserting variables into templates means this isn't the case. Every option and default appears in values.yaml and it's a one stop shop to see everything you can customize. The code example you wrote could be better written as:
containers:
- name: frontend
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
With values.yaml having image:
repository: my_default_image
tag: my_default_tag
Note that values.yaml is part of the template and values passed to helm's cli can override individual values in it.I'm not sure what you mean about helm charts having no upgrade path. IME you can un-deploy, upgrade, and rollback helm deployments and it takes care of adding/removing kube resources that where also added or removed in the yaml for you. [1]