I am currently writing a Helm chart for a multi-container application. We have a bunch of microservice containers (we call them "applications") that are very similar in the way they can be handled through K8s, and can (and thus should) be handled by the same Helm template to avoid duplicating things. On the other hand, it makes sense to be able to configure certain settings individually for the different applications (e.g., resource requests). I am currently doing something like this:
{{- $applications:= <obtain list of applications> }}
{{ range $app:= $applications }}
apiVersion: apps/v1
kind: StatefulSet
spec:
[...]
spec:
containers:
- name: {{ $app }}
image: {{ $.Values.image.registry }}mycompany/myproduct-{{ $app }}:{{ $.Values.image.version }}
[...]
What I would like to do now is be able to set some application specific values (take K8s resources.requests.memory or number of replicas as an example) that can be set individually inside values.yaml for each application, but falls back to a default if they are not set. The idea was to have such a section in values.yaml:
applications:
default:
replicas: 1
resources:
requests:
memory: 512Mi
cpu: 250m
applicationA:
resources:
requests:
memory: 7Gi
applicationB:
resources:
requests:
cpu: 500m
[...]
The idea is that I use the value from the "default" section for applications, unless there is an application-specific value specified in the section for the respective application. In my example, I have a custom value for the memory request of applicationA and one for the CPU request of application B, but all other values should come from the default section. There can also be applications where no application-specific settings are defined at all (in which case everything is coming from the default section of values.yaml). The "index" function seemed to allow me to do what I want, so in my template, I tried this (line break for readability):
resources:
requests:
memory: {{ default \
(index $.Values "applications" "default" "resources" "requests" "memory") \
(index $.Values "applications" $app "resources" "requests" "memory") }}
Since the index allows me to use the value of my loop variable "$app" to "dereference" a value from values.yaml, this actually works... alas, index fails with error calling index: index of nil pointer in those cases where I do not specify an appliation-specific value for one of the settings, and thus the dereferencing fails. What I would need is index to NOT fail in that situation, but just return an empty value, so that the default would kick in. Unfortunately, I cannot seem to find a way to do this.
But maybe there is a complete different way of handling this problem, so any ideas and suggestions are appreciated. Of course as a fallback I could just explicitly set every value for each application in values.yaml, but that just does not feel right.