What is the best way of creating Helm Charts in a single repository for different deployment environments? - kubernetes

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.

Related

Add key value pair to helm values.yaml file

I have a use case to write a randomly generated password back to values.yaml file.
I don't want to use install or upgrade command, having a hard time reading through documentation.
Apart from going through the helm way, I tried updating values.yaml file through yq command but it is removing the comments in the file.

Kubernetes + Helm - only restart pods if new version/change

Whenever I run my basic deploy command, everything is redeployed in my environment. Is there any way to tell Helm to only apply things if there were changes made or is this just the way it works?
I'm running:
helm upgrade --atomic MyInstall . -f CustomEnvironmentData.yaml
I didn't see anything in the Helm Upgrade documentation that seemed to indicate this capability.
I don't want to bounce my whole evironment unless I have to.
There's no way to tell Helm to do this, but also no need. If you submit an object to the Kubernetes API server that exactly matches something that's already there, generally nothing will happen.
For example, say you have a Deployment object that specifies image: my/image:{{ .Values.tag }} and replicas: 3. You submit this once with tag: 20200904.01. Now you run the helm upgrade command you show, with that tag value unchanged in the CustomEnvironmentData.yaml file. This will in fact trigger the deployment controller inside Kubernetes. That sees that it wants 3 pods to exist with the image my/image:20200904.01. Those 3 pods already exist, so it does nothing.
(This is essentially the same as the "don't use the latest tag" advice: if you try to set image: my/image:latest, and redeploy your Deployment with this tag, since the Deployment spec is unchanged Kubernetes won't do anything, even if the version of the image in the registry has changed.)
You should probably use helm diff upgrade
https://github.com/databus23/helm-diff
$ helm diff upgrade - h
Show a diff explaining what a helm upgrade would change.
This fetches the currently deployed version of a release
and compares it to a chart plus values.
This can be used visualize what changes a helm upgrade will
perform.
Usage:
diff upgrade[flags] [RELEASE] [CHART]
Examples:
helm diff upgrade my-release stable / postgresql--values values.yaml
Flags:
-h, --help help for upgrade
--detailed - exitcode return a non - zero exit code when there are changes
--post - renderer string the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path
--reset - values reset the values to the ones built into the chart and merge in any new values
--reuse - values reuse the last release's values and merge in any new values
--set stringArray set values on the command line(can specify multiple or separate values with commas: key1 = val1, key2 = val2)
--suppress stringArray allows suppression of the values listed in the diff output
- q, --suppress - secrets suppress secrets in the output
- f, --values valueFiles specify values in a YAML file(can specify multiple)(default[])
--version string specify the exact chart version to use.If this is not specified, the latest version is used
Global Flags:
--no - color remove colors from the output

Choosing between alternative dependencies in helm

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 -}}

Kubernetes Helm chart requirements.yaml file dependencies false condition

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.

Un-hardcode deploy config image tag name

Right now our DC (deployment config) has this hardcoded it it:
/// dc.yaml
image: containers.nabisco.com/cdt-org/cdt-dev:latest
then we roll out the dc with:
$ oc rollout latest dc/cdtcae-prod-deployment
however one problem I am noticing is that sometimes the "latest" tag refers to an old one and the newer one doesn't get pulled in - might be a bug with OpenShift or Kubernetes or what not.
we want to use git commit hashes to uniquely identify deployments, for the moment.
My question is - is there a way to override / update the image: line above, using the command line, so this line:
image: containers.nabisco.com/cdt-org/cdt-dev:latest
would get overriden by something like this:
oc rollout --tag="$my_git_commit_hash" dc/cdtcae-prod-deployment
I heard that the best option would be to use the following setting in your yaml DC config:
imagePullPolicy: "Always"
then you can just hard code some unique value
image: containers.nabisco.com/cdt-org/cdt-dev:foobarbaz
and it will always pull the latest one, instead of using the cache.