I have a HELM Chart with a few requirements (i.e. subcharts).
When deploying that chart, I use a values.yaml containing all the values for both the main chart and the subcharts :
globalFoo: "bar"
subchart1:
foo: subchart1-{{ globalFoo }}
subchart2:
localFoo: "bar2"
foo: subchart2-{{ subchart2.localFoo }}
I'd like to achieve two things :
Reference a previously declared global variable (i.e. in the global chart scope) in a subchart value (subchart1.foo in my example)
Reference a previously declared local variable in the same subchart scope (subchart2.foo in my example)
The exemple above doesn't work. I tried several syntaxes and none of them worked. I didn't find anything like that in the HELM documentation.
Is it doable ?
Reference a previously declared global variable in a subchart value, Reference a previously declared local variable in the same subchart scope
This can be achieved to some extent using anchors and aliases.
global:
foo: &global-foo bar
subchart1:
# this verbatim copies the content of the anchor
foo: *global-foo
local: &subchart1-local bar
subchart2:
foo: *subchart1-local
Values can naturally be combined in a helm template:
kind: ConfigMap
...
data:
FOO: "subchart2-{{ .Values.subchart2.foo }}"
If find yourself needing "templated values" the tpl function may be helpful:
# values
global:
user: foo
pass: bar
dbhost: dbserver.com
mychart:
connection: "db://{{.d.user}}:{{d.pass}}/{{d.dbhost}}"
# template
kind: ConfigMap
...
data:
DBURL: "{{ tpl .Values.mychart.connection (dict "d" .Values.global "Template" $.Template }}"
Note the (dict ...) syntax is derived from a hint in this helm github comment. This helps to shorten the template string by giving the ".d" context instead ".Values", i.e. .d.user is short for .Values.global.user
Currently (as of Helm version 3) this is not supported.
A similar issue is discussed in Proposal: Allow templating in values.yaml
And is rejected for several reasons. One of them stated by the creator of Helm
The bigger constraint is that the values.yaml file MUST always be a valid YAML file.
And also in Support for using {{ values }} within values.yaml
the file that is passed into the template engine as a source of data for templates is itself not passed through the template engine. We almost definitely will not do that because it gets very confusing for users. It also breaks both standard YAML compatibility and backward compatibility with all existing Helm versions.
And last but not least here
The tl;dr
At its most simple, the reason behind not wanting to do this is you don’t template the file that provides the values that you template with. Furthermore, this feature will be made obsolete by Helm 3
...
Obsolete by Helm 3
In Helm 3 as part of the eventing/hook system, we will allow Lua-based modification of values in a much easier way than having to template them out. Seeing as we are well underway with development for Helm 3, adding a feature with all of the drawbacks mentioned above would cause more churn than the value added. So we aren’t rejecting this outright, but are implementing it (albeit in a different way) for Helm 3
But the mentioned support via Lua has been closed with this comment
We should close this as Lua support is not coming anytime soon and we have other (arguably better) ideas on handling this (like WASM). This was in the plan but isn't any longer.
Related
I got into a scenario where I need to create a deployment template to use multiple value files one after the another without merging or overriding.
The valueFiles as specified in argoCD application yaml file under valueFiles parameter.
Can someone help on how to overcome this situation. I need to create a helm template which should take value file one after another using some range function or so.
Thanks in advance
A simple helm template example to use pass multiple value files one after another to a helm template.
We have a set of Micro-Services (MS-a, MS-b, MS-c..) each has its own dependencies specified in requirements.yaml. Some have the same requirements, e.g mongodb.
For deployment of the overall application we created an umbrella-chart that references all MSs as its dependencies in requirements.yaml.
We provide a single values.yaml file to the umbrella-chart. That contains all the values for all the MS charts. That works fine till it comes to providing values to all the dependency charts of MS charts.
One prominent example would be mongodb.clusterDomain
In values.yaml file the clusterDomain value would have to be repeated for each MS section:
MS-a:
mongodb:
clusterDomain: cluster.local
MS-b:
mongodb:
clusterDomain: cluster.local
that screams for trouble, when it comes to maintainability. Is there a way to move those values to some global section, so that it is only specified once ? e.g:
global:
mongodb:
clusterDomain: cluster.local
I have tried to use anchors https://helm.sh/docs/chart_template_guide/yaml_techniques/#yaml-anchors
it would look like that:
global:
mongodb:
clusterDomain: &clusterDomain cluster.local
MS-a:
mongodb:
clusterDomain: *clusterDomain
MS-b:
mongodb:
clusterDomain: *clusterDomain
It does not reduce the structure complexity, but it makes it easier to maintain, because the value needs to be set in one place only.
however, it seems to have a very nasty pitfall when it comes to overriding values via --set.
According to the link above:
While there are a few cases where anchors are useful, there is one aspect of them that can cause subtle bugs: The first time the YAML is consumed, the reference is expanded and then discarded.
It practically means it will not be possible to override the clusterDomain values by providing:
--set global.mongodb.clusterDomain=cluster.local
because it will only replace the global section, while all the other places will remain with their original value.
Is there any other way(s) to make it possible to set subcharts values globally in one place?
I have a helm chart for an application that needs some kind of database.
Both mysql or postgresql would be fine.
I would like to give the chart user the option to install one of these as a dependency like this:
dependencies:
- name: mysql
version: 0.10.2
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mysql.enabled
- name: postgresql
version: 3.11.5
repository: https://kubernetes-charts.storage.googleapis.com/
condition: postgresql.enabled
However this makes it possible to enable both of them.
Is there an easy way to make sure only one is selected?
I was thinking of a single variable selecting one of [mysql, postgres, manual] and depend on a specific database if it is selected. - Is there a way to do so?
I don't think there's a straightforward way to do this. In particular, it looks like the requirements.yaml condition: field only takes a boolean value (or a list of them) and not an arbitrary expression. From the Helm documentation:
The condition field holds one or more YAML paths (delimited by commas). If this path exists in the top parent’s values and resolves to a boolean value, the chart will be enabled or disabled based on that boolean value. Only the first valid path found in the list is evaluated and if no paths exist then the condition has no effect.
(The tags mechanism described below that is extremely similar and doesn't really help.)
When it comes down to actually writing your Deployment spec you have a more normal conditional system and can test that only one of the values is set; so I don't think you can prevent having redundant databases installed, but you'll at least only use one of them. You could also put an after-the-fact warning to this effect in your NOTES.txt file.
{{ if and .Values.mysql.enabled .Values.postgresql.enabled -}}
WARNING: you have multiple databases enabled in your Helm values file.
Both MySQL and PostgreSQL are installed as part of this chart, but only
PostgreSQL is being used. You can update this chart installation setting
`--set mysql.enabled=false` to remove the redundant database.
{{ end -}}
I am using the Kubernetes Helm requirements.yaml file for dependencies addition. Based on the values.yaml condition, it will create the dependencies pods.
Here I want to execute required dependencies when apache.enabled == false
values.yaml
external_apache:
enabled: false
File requirements.yaml
dependencies:
- name:
version:
repository:
condition: external_apache.enabled
How do I add a false condition?
I have tried the below condition, but it's not working:
condition: external_apache.enabled == false
What version of Helm are you using?
There was a similar issue in the Kubernetes repository on GitHub:
Unable to use condition in 'requirements.yaml' #2111
The solution was to upgrade Helm to v2.2.0+. In that version, condition support was added.
Helm 2 to Helm 3 upgrade note:
Chart apiVersion bumped to "v2" for following specification changes:
Dynamically linked chart dependencies moved to Chart.yaml (requirements.yaml removed and requirements --> dependencies)
Library charts (helper/common charts) can now be added as dynamically linked chart dependencies
Charts have a type metadata field to define the chart to be of an application or library chart. It is application by default which means it is renderable and installable
Helm 2 charts (apiVersion=v1) are still installable
In the Helm documentation or repository, there is an explanation of how the condition works:
(I've added some comments to make reading easier)
Condition - The condition field holds one or more YAML paths (delimited by commas).
Tags - The tags field is a YAML list of labels to associate with this chart.
# parentchart/requirements.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled, global.subchart1.enabled
tags:
- front-end #(chart should be disabled because the tags.front-end is “false” in values.yaml file , but ...)
- subchart1 #(subchart1.enabled condition path is present in values.yaml file and it has "true" value...)
#(this condition, so it overrides tag front-end and this chart will be enabled)
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled,global.subchart2.enabled
#(as soon as no one from these paths is exists in values.yaml this condition has ho effect)
tags:
- back-end #(chart should be enabled because the tags.back-end is “true” in values.yaml file)
- subchart2 #(and there is no condition path found in values.yaml to override it)
If this condition path exists in the top parent’s values and resolves to a boolean value, the chart will be enabled or disabled based on that boolean value.
Only the first valid path found in the list is evaluated and if no paths exist then the condition has no effect.
In the top parent’s values, all charts with tags can be enabled or disabled by specifying the tag and a boolean value.
# parentchart/values.yaml
subchart1:
enabled: true #(this could be found from requirements as subchart1.enabled and override tags in this case)
tags:
front-end: false #(this disables charts with tag front-end)
back-end: true #(this enables charts with tag back-end)
The logic and sequence of conditions and tags are described in Tags and Condition Resolution:
Conditions (when set in values) always override tags. The first condition path that exists wins and subsequent ones for that chart are ignored.
Tags are evaluated as ‘if any of the chart’s tags are true then enable the chart’.
Tags and conditions values must be set in the top parent’s values.
The tags: key in values must be a top level key. Globals and nested tags: tables are not currently supported.
You can also set tags and conditions in the command line:
helm install --set tags.front-end=true --set subchart2.enabled=false
Helm version v2.2.2 worked, while v2.10.0 didn't.
Based on the documentation and the answer from #VAS, the answer to your question is it's not possible to use a negation of a condition in requirements.yaml.
Though its a bit late, but users may find it helpful. I am not running helm install for the parent chart from command line, but, I have a shell script for running it and another shell script for environment properties.
I have set the conditional boolean values to true or false in environment script and using the values in other script which runs helm for parent helm chart, I have set individual child chart enabled property in parent's values.yaml.
Also, in version 3.0.0+, the configuration done earlier in
requirements.yaml are now done in parent's chart.yaml itself.
We are using Helm Charts for deploying a service in several environments on Kubernetes cluster. Now for each environment there are a list of variables like the database url, docker image tag etc. What is the most obvious and correct way of defining Helm related values.yaml in such case where all the Helm template files remain same for all the environment except for some parameters as stated above.
One way to do this would be using multiple value files, which helm now allows. Assume you have the following values files:
values1.yaml:
image:
repository: myimage
tag: 1.3
values2.yaml
image:
pullPolicy: Always
These can both be used on command line with helm as:
$ helm install -f values1.yaml,values2.yaml <mychart>
In this case, these values will be merged into
image:
repository: myimage
tag: 1.3
pullPolicy: Always
You can see the values that will be used by giving the "--dry-run --debug" options to the "helm install" command.
Order is important. If the same value appears in both files, the values from values2.yaml will take precedent, as it was specified last. Each chart also comes with a values file. Those values will be used for anything not specified in your own values file, as if it were first in the list of values files you provided.
In your case, you could specify all the common settings in values1.yaml and override them as necessary with values2.yaml.