I have the following project structure:
some-module1
templates
deployment.yaml
values.yaml
some-module2
templates
deployment.yaml
values.yaml
some-module3
templates
deployment.yaml
values.yaml
global-config
templates
secrets.yaml
values.yaml
The values.yaml files for some-module1, some-module2, and some-module3 contain the same section:
shards:
- name: "db1"
url: "url1"
login: "login1"
password: "password1"
- name: "db2"
url: "url2"
login: "login2"
password: "password2"
The deployment.yaml files for some-module1, some-module2, and some-module3 contain the following identical part:
{{- range $name, $val := .Values.shards }}
env:
- name: DB_URL
value: {{ $val.url }}
- name: DB_LOGIN
value: {{ $val.login }}
- name: DB_PASSWORD
value: {{ $val.password }}
{{- end }}
I have two tasks:
Move the shards configuration to global-config/values.yaml. Move all sensitive data from global-config/values.yaml (under shards) to secrets in global-config/secrets.yaml. As a result, some-module1, some-module2, and some-module3 should read the shards data from the global config (i.e., the loop should look like {{- range $name, $val := .Values.global.shards }}), and all sensitive data should be sourced from the secrets.
Is this possible? If yes, how can I achieve this?
I have the following project structure:
some-module1
templates
deployment.yaml
values.yaml
some-module2
templates
deployment.yaml
values.yaml
some-module3
templates
deployment.yaml
values.yaml
global-config
templates
secrets.yaml
values.yaml
The values.yaml files for some-module1, some-module2, and some-module3 contain the same section:
shards:
- name: "db1"
url: "url1"
login: "login1"
password: "password1"
- name: "db2"
url: "url2"
login: "login2"
password: "password2"
The deployment.yaml files for some-module1, some-module2, and some-module3 contain the following identical part:
{{- range $name, $val := .Values.shards }}
env:
- name: DB_URL
value: {{ $val.url }}
- name: DB_LOGIN
value: {{ $val.login }}
- name: DB_PASSWORD
value: {{ $val.password }}
{{- end }}
I have two tasks:
Move the shards configuration to global-config/values.yaml. Move all sensitive data from global-config/values.yaml (under shards) to secrets in global-config/secrets.yaml. As a result, some-module1, some-module2, and some-module3 should read the shards data from the global config (i.e., the loop should look like {{- range $name, $val := .Values.global.shards }}), and all sensitive data should be sourced from the secrets.
Is this possible? If yes, how can I achieve this?
Share Improve this question asked Feb 2 at 11:16 AidarKhaibulovAidarKhaibulov 112 bronze badges1 Answer
Reset to default 1There's a couple of parts here, and some are easier than others.
The duplicated output block. If you have the same block of output YAML that you're repeating in several places, you can split that into a named template. For example,
{{/* env.db generates part of an env: block that sets database-specific
parameters. Takes a shard object as a parameter. Unindented, ends
with a newline. */}}
{{- define "env.db" -}}
- name: DB_URL
value: {{ .url }}
- name: DB_LOGIN
value: {{ .login }}
- name: DB_PASSWORD
value: {{ .password }}
{{ end -}}
{{- range $name, $val := .Values.shards }}
env:
{{ include "env.db" $val | indent 2 }}
{{- end -}}
Having done that, you can move the template definition into a library chart. This could be something like moving the {{ define }}...{{ end }}
block into your existing global-secrets/templates/_helpers.tpl
file. The main charts would need to include a dependency on the library chart in their Chart.yaml
files, but then they could call the template in exactly the same way.
Note that, if you define a function in a library chart, settings like .Values
come from the place it's called, not the place it's defined. So it won't work to put the credential in the library chart too, it needs to be defined in the per-service chart.
The duplicated input settings. You can pass arbitrarily many helm install -f
options to add values files when you deploy a chart, and these are used in addition to the chart's values.yaml
file. One possible setup here is that your CD system can extract the credentials from a secret store and write them out as a YAML (or JSON) file, and then run
helm upgrade --install mod1 ./some-module1 --namespace mod1 \
-f values-credentials.yaml
I would avoid putting these values under the special global:
top-level key; that's only useful when you have multiple levels of nested charts or settings that are the same across multiple components being installed in the same Helm invocation. Also note (see same documentation link) that a dependency's global:
settings do not propagate upward to the main chart: if the credentials are in global-config/values.yaml
and the main chart depends on them, the main chart (including the include
call above) will not be able to see those values.
Using a Secret instead of Helm values. Well, you can, I guess, there's a supported path in Helm to do this. I'd avoid having external dependencies like this if you can. In the previous section I suggested using some sort of credential store and having automation generate parts of the values, and it could kubectl get secret
and base64-decode the values if you don't have anything better available.
Helm does have a lookup
function that can find arbitrary resources in the cluster. You can, in principle, get a Secret value like
{{- $secret := lookup "v1" "Secret" .Release.Namespace "secret-name" -}}
{{- $password := $secret.data.password | b64dec -}}
You could reuse the $secret
but you'd have to do something like the second line for each value you want to get out of the Secret. Helm doesn't have a couple of standard functional-programming tools like "map" that would make a more generic solution possible. You'd also have to tolerate cases where the Secret doesn't exist, and figure out how to develop and test the chart without access to the production Secret. If the Secret changes in the cluster, the Helm chart won't redeploy itself, and you'll need to remember to do this by hand.
(If you want the deployment to be driven by Kubernetes resources, consider writing a custom operator, maybe in Go using Kubebuilder. It is not harder than writing a really robust Helm chart once you start getting into complexities around library charts, and Go is a much more mainstream language that includes a unit-testing framework.)
Use a Secret as a source for Helm values. Helm doesn't have a way to do this. If the credential was only in a Secret, and you didn't have automation to pull it out, then nothing in Helm itself would let you refer to it as part of .Values
. You'd need to invoke lookup
as above.
To reiterate:
- I would break the repeated environment block out into a library chart that you control.
- I would not try to do anything to avoid repeating blocks of
values.yaml
settings. - I would have your deployment system get the right credentials from somewhere and inject them with a
helm install -f
option. - I would not try to put settings into a Kubernetes Secret.