overriding values in kubernetes helm subcharts - kubernetes

I'm building a helm chart for my application, and I'm using stable/nginx-ingress as a subchart. I have a single overrides.yml file that contains (among other overrides):
nginx-ingress:
controller:
annotations:
external-dns.alpha.kubernetes.io/hostname: "*.{{ .Release.Name }}.mydomain.com"
So, I'm trying to use the release name in the overrides file, and my command looks something like: helm install mychart --values overrides.yml, but the resulting annotation does not do the variable interpolation, and instead results in something like
Annotations: external-dns.alpha.kubernetes.io/hostname=*.{{ .Release.Name }}.mydomain.com
I installed the subchart by using helm fetch, and I'm under the (misguided?) impression that it would be best to leave the fetched thing as-is, and override values in it - however, if variable interpolation isn't available with that method, I will have to put my values in the subchart's values.yaml.
Is there a best practice for this? Is it ok to put my own values in the fetched subchart's values.yaml? If I someday helm fetch this subchart again, I'll have to put those values back in by hand, instead of leaving them in an untouched overrides file...
Thanks in advance for any feedback!

I found the issue on github -- it is not supported yet:
https://github.com/kubernetes/helm/issues/2133

Helm 3.x (Q4 2019) now includes more about this, but for chart only, not for subchart (see TBBle's comment)
Milan Masek adds as a comment:
Thankfully, latest Helm manual says how to achieve this.
The trick is:
enclosing variable in " or in a yaml block |-, and
then referencing it in a template as {{ tpl .Values.variable . }}
This seems to make Helm happy.
Example:
$ cat Chart.yaml | grep appVersion
appVersion: 0.0.1-SNAPSHOT-d2e2f42
$ cat platform/shared/t/values.yaml | grep -A2 image:
image:
tag: |-
{{ .Chart.AppVersion }}
$ cat templates/deployment.yaml | grep image:
image: "{{ .Values.image.repository }}:{{ tpl .Values.image.tag . }}"
$ helm template . --values platform/shared/t/values.betradar.yaml | grep image
image: "docker-registry.default.svc:5000/namespace/service:0.0.1-SNAPSHOT-d2e2f42"
imagePullPolicy: Always
image: busybox
Otherwise there is an error thrown..
$ cat platform/shared/t/values.yaml | grep -A1 image:
image:
tag: {{ .Chart.AppVersion }}
1 $ helm template . --values platform/shared/t/values.yaml | grep image
Error: failed to parse platform/shared/t/values.yaml: error converting YAML to JSON: yaml: invalid map key: map[interface {}]interface {}{".Chart.AppVersion":interface {}(nil)}
For Helm subchart, TBBle adds to issue 2133
#MilanMasek 's solution won't work in general for subcharts, because the context . passed into tpl will have the subchart's values, not the parent chart's values.
!<
It happens to work in the specific example this ticket was opened for, because .Release.Name should be the same in all the subcharts.
It won't work for .Chart.AppVersion as in the tpl example.
There was a proposal to support tval in #3252 for interpolating templates in values files, but that was dropped in favour of a lua-based Hook system which has been proposed for Helm v3: #2492 (comment)
That last issue 2492 include workarounds like this one:
You can put a placeholder in the text that you want to template and then replace that placeholder with the template that you would like to use in yaml files in the template.
For now, what I've done in the CI job is run helm template on the values.yaml file.
It works pretty well atm.
cp values.yaml templates/
helm template $CI_BUILD_REF_NAME ./ | sed -ne '/^# Source:
templates\/values.yaml/,/^---/p' > values.yaml
rm templates/values.yaml
helm upgrade --install ...
This breaks if you have multiple -f values.yml files, but I'm thinking of writing a small helm wrapper that runs essentially runs that bash script for each values.yaml file.
fsniper illustrates again the issue:
There is a use case where you would need to pass deployment name to dependency charts where you have no control.
For example I am trying to set podAffinity for zookeeper. And I have an application helm chart which sets zookeeper as a dependency.
In this case, I am passing pod antiaffinity to zookeeper via values. So in my apps values.yaml file I have a zookeeper.affinity section.
If I had the ability to get the release name inside the values yaml I would just set this as default and be done with it.
But now for every deployment I have to override this value, which is a big problem.
Update Oct. 2022, from issue 2133:
lazychanger proposes
I submitted a plugin to override values.yaml with additional templates.
See lazychanger/helm-viv: "Helm-variable-in-values" and its example.

Related

Helm template - Overriding values file

I am currently trying to test some changes, specifically to see if a chart picks up/inherits changes from a top level values file. This top level values file should override any settings in the values file for this chart. To test this, I am trying to use the following command:
helm template --values path/to/top/level/values.yaml path/to/chart > output.yaml
However, when viewing the output for this, the chart still retains the values defined in the chart, and not the values that have been set in the top level values file.
I have tried a number of variations of this command, such as:
helm template path/to/chart --values path/to/top/level/values.yaml > output.yaml
helm template -f path/to/chart/values.yaml --values path/to/top/level/values.yaml > output.yaml
helm template path/to/top/level/values.yaml --values path/to/chart > output.yaml
Am I using this command correctly? Is what I am trying to achieve only possible when doing a helm install or upgrade? e.g. https://all.docs.genesys.com/PrivateEdition/Current/PEGuide/HelmOverrides
Overriding values from a parent (you call it top-level) chart mychart works like a charm and exactly as described in the Helm docs.
A values.yaml in folder mychart/charts/mysubchart
dessert: cake
can be overriden by a values.yaml in folder mychart
mysubchart:
dessert: ice cream
Any directives inside of the mysubchart section will be sent to the mysubchart chart.
Rendering the parent (top-level) chart works like that:
helm template mychart -f mychart/values.yaml
What if what you want is to combine from 2 yaml files, is it possible?
Example:
values.yaml:
blackBoxSidecar:
enabled: true
targets:
- target: esb:443
module: tcp_connect
values-namespace.yaml:
blackBoxSidecar:
targets:
- target: rabbitmq-namespace:443
module: tcp_connect
What I want to get is:
blackBoxSidecar:
enabled: true
targets:
- target: esb:443
module: tcp_connect
- target: rabbitmq-namespace:443
module: tcp_connect

Syntax Error in Yaml File - missed comma between flow collection entries

We have an application deployed in AKS , the kubernetes version we were using is 1.15 now we want to upgrade the Kubernetes to 1.16, I notice that some of the APIs have been deprecated in 1.16.We have deployment.yaml file in which I had to change the from
apiVersion: extensions/v1beta1 to apiVersion: apps/v1 for Deployment.
after doing this change I see that the deployment YAML is failing lint test for another entry :
- name : APP_HOST
{{- range $host := .Values.ingress.hosts }}
value: {{ $host }}
{{- end }}
Error :
npx yaml-lint yamllint deployment.yaml
npx: installed 45 in 14.04s
× YAML Lint failed for deployment.yaml
× missed comma between flow collection entries at line 88, column 11:
{{- range $host := .Values.ingress ...
Can some one help me with the syntax needed for this. Mind you it was working fine before. Not sure if I have added and extra space or corrupted the file.
Thanks
The syntax you have looks like a correct Helm template, including correct whitespace controls. However, it is not valid YAML; the template {{ ... }} syntax looks at least a little bit like an inline mapping { key: value }, and this confuses the linter.
You can't run the un-rendered Helm template files through yamllint or another plain YAML validator. You can run helm template to render the template to plain text, and then run yamllint on that. The current version of Helm will try to parse the produced YAML as it generates it, so just running helm template will give you some protection against whitespace errors.

How can we specify custom path to .Files.Get when creating ConfigMap with Helm

I am creating a config map as below
kubectl create configmap testconfigmap --from-file=testkey=/var/opt/testfile.txt
As I am using helm charts, I would like to create the config map using YAML file instead of running kubectl.
I went through Kubernetes - How to define ConfigMap built using a file in a yaml? and we can use .Files.Get to access the files.
But then testfile.txt needs to be a part of helm. I would like to have something like
kind: ConfigMap
metadata:
name: testconfigmap
data:
fromfile: |-
{{ .Files.Get "/var/opt/testfile.txt" | indent 4 }}
It works when "testfile.txt" is under the main helm directory. So, {{ .Files.Get "testfile.txt" | indent 4 }} works but {{ .Files.Get "/var/opt/testfile.txt" | indent 4 }} doesn't. With custom path, the value for the ConfigMap is empty.
Is is possible to place the file at a custom path outside the helm folder, so I can define my path in Values.yaml and read it in my ConfigMap yaml ?
This is a Community Wiki answer so feel free to edit it and add any additional details you consider important.
As mdaniel has already stated in his comment:
Is is possible to place the file at a custom path outside the helm
folder no, because helm considers that a security risk – mdaniel 2
days ago
You can also compare it with this feature request on GitHub where you can find very similar requirement described in short e.g. in this comment:
I have this exact need. My chart publishes a secret read from file at
/keybase. This file is deliberately not in the chart.
I believe files for .Files.Get should not be assumed to be inside the
chart ...
One interesting comment:
lenalebt commented on Dec 23, 2017 I am quite sure .Files.Get not
being able to access the file system arbitrarily is a security
feature, so I don't think the current behaviour is wrong - it just
does not fulfill all use cases.
This issue was created quite long time ago (Dec 19, 2017) but has been recently reopened. There are even some specific proposals on how it could be handled:
titou10titou10 commented on Apr 2 #misberner can you confirm that
using--include-dir =will allow us to use
.Files.Glob().AsConfig(), and so create a ConfigMap with one
entry in the CM per file in?
#misberner misberner commented on Apr 2 Yeah that's the idea. An open
question from my point of view is whether an --include-dir with a
specified introduces an overlay, or shadows everything under
/ from previous args and from the bundle itself. I'm not super
opinionated on that one but would prefer the former.
The most recent comments give some hope that this feature might become available in future releases of helm.
As mdaniel and mario already mentioned, for now this is not possible, as it's considered a security risk.
But actually there is a workaround.
You can use Helm templating to parse your property file and load it into a ConfigMap.
# create the following ConfigMap in your Chart
# this is just a simple prototype
# it requires strict key=value syntax in your property file (no empty strings etc.)
# but it shows the idea - improve the syntax, if needed
apiVersion: v1
kind: ConfigMap
metadata:
name: example
data:
{{- if .Values.example.map }}
{{- range $line := splitList "\n" .Values.example.map }}
{{- $words := splitList "=" $line }}
{{- $key := index $words 0 | trim }}
{{- $value := rest $words | join "=" | trim }}
{{ $key }}: "{{ $value }}"
{{- end }}
{{- end }}
{{- end }}
And after that you may load your properties file into this ConfigMap.
helm install mychart --set-file example.map="/test/my.properties"
Of course it is safe to use ONLY if you fully control the input, i. e. how each and every line of your property file is populated.

helm template values and set variables

I have this section in my service template. I want, if variable publicIP is defined, define loadBalancerIP.
{{- if .Values.publicIP }}
loadBalancerIP: {{ .Values.publicIP }}
{{- end }}
in my values.$environment.yml
I define
publicIP: null
And I need to define publicIP when I do helm install, for example:
helm install release release/path -f values.$environment.yml -—set publicIP=127.0.0.1
But it isn't working. What can I do to define publicIP and it defines in my template?
I am not sure I understand the question but if you want to set an individual parameter you need to do it with
"--set"
eg : helm install --set foo=bar ./mychart
What is the name of your values.yml? values.$environment.yml?
Try also command like this
helm install release release/path -f --values {YOUR_VALUES_FILE}.yml --set publicIP=127.0.0.1
and be sure to use --, you seem in the example provided to use a weird special character much longer than a normal dash.
And second is publicIP a root parameter?
if you have something like this in {YOUR_VALUES_FILE}.yml
root
node: null
you need to set it like this :
helm install release release/path -f --values {YOUR_VALUES_FILE}.yml --set root.node=value

How to pass a file using values file in helm chart?

I want to pass a certificate to the helm chart and currently I am passing using --set-file global.dbValues.dbcacertificate=./server.crt but instead i want to pass the file in values file of helm chart.
The Values.yaml file reads
global:
dbValues:
dbcacertificate: <Some Way to pass the .crt file>
According to the relevant documentation, one must pre-process a file that is external to the chart into a means that can be provided via --set or --values, since .Files.Get cannot read file paths that are external to the chart bundle.
So, given the following example template templates/secret.yaml containing:
apiVersion: v1
kind: Secret
data:
dbcacertificate: {{ .Values.dbcacertificate | b64enc }}
one can use shell interpolation as:
helm template --set dbcacertificate="$(cat ./server.crt)" .
or, if shell interpolation is not suitable for your circumstances, you can pre-process the certificate into a yaml compatible format and feed it in via --values:
$ { echo "dbcacertificate: |"; sed -e 's/^/ /' server.crt; } > ca-cert.yaml
$ helm template --values ./ca-cert.yaml .