How can I do this in a Helm chart's values.yaml file? - kubernetes-helm

We deploy our microservices in multiple AWS regions. I therefore want to be able to do this in a Helm chart values.yaml file.
# Default region
aws_region: us-east-1
aws_ecrs:
us-east-1: 01234567890.dkr.ecr.us-east-1.amazonaws.com
eu-north-1: 01234567890.dkr.ecr.eu-nort-1.amazonaws.com
image:
name: microservice0
repository: {{ .Values.aws_ecrs.{{ .Values.aws_region }} }} # I know this is incorrect
So now when I install the chart, I just want to do
$ helm install microservice0 myChart/ --set aws_region=eu-north-1
and the appropriate repository will be assigned to .Values.image.repository. Can I do this? If so what is the correct syntax?
NOTE: The image repository is just one value that depends on the AWS region, we have many more other values that also depend on the AWS region.

Pass the repository name as an ordinary Helm value.
# templates/deployment.yaml
image: {{ .Values.repository }}/my-image:{{ .Values.tag }}
Create a separate file per region. This does not necessarily need to be in the same place as the Helm chart. Provide the regional values as ordinary top-level values. You'll have multiple files that provide the same values and that's fine.
# eu-north-1.yaml
repository: 01234567890.dkr.ecr.eu-nort-1.amazonaws.com
Then when you deploy the chart, use the helm install -f option to use the correct per-region values. These values will override anything in the chart's values.yaml file, but anything you don't specifically set here will use those default values from the chart.
helm install microservice0 myChart/ \
--set-string tag=20220201 \
-f eu-north-1.yaml
You can in principle use the Go template index function to do the lookup as you describe; the top-level structure in Variable value as yaml key in helm chart is similar to what you show in the question. This is more complex to implement in the templating code, though, and it means you have different setups for the values that must vary per region and those that can't.

Related

purpose of PLACEHOLDER entry in kubernetes yaml files

Why write non-secret metadata as PLACEHOLDER in kubernetes yaml files? (from here):
namespace: PLACEHOLDER
Any reason to replace it with a later sed command? why not simply write it inside the yaml file?
Those values are normally replaced or overridden later, either by sed within a CI/CD pipeline like Jenkins, or (as indicated by the question you linked to) by Helm.
With helm, you can override values within the yamls either with a second yaml, or at the command line using --set switches.
So I could have
helm install nginx --values values.yaml --values values2.yaml
and the placeholder value in values.yaml would get overridden by the value in values2.yaml
Placeholders are often used to deliberately break an install is someone tries to install it without passing in the right values.yaml
For example:
helm install my-chart
Could break because of the placeholder value, but
helm install my-chart --values production.values.yaml
would install because the placeholder values are overridden and the chart can install correctly.
Based on my experience, when you see files like this, they might be used in some sort of pipelines to deploy them in multiple clusters. These files, from my prior experience, act like templates when you don't want to go all in with Helm charts for a single ConfigMap or Secret or a different isolated resource. This allows you to replace these placeholders with values corresponding with you cluster, region etc.
Hope this makes sense.

How to maintain a separate values file for a dependency Helm subchart that is shared with the parent chart?

I'm building a Helm chart that depends on another chart (let's say, "kafka" from bitnami repo). I declared this other chart as a dependency in my Chart.yaml:
dependencies:
- name: kafka
version: 14.0.5
repository: https://charts.bitnami.com/bitnami
Now I can set the values for this dependency chart in the top-level kafka section of my values.yaml. So far, so good.
What if I also need to run "kafka" chart independently with the same values? Let's say I extract them into a separate kafka-values.yaml. In this case, will I be able to reuse this separate file when I'm deploying the parent chart?
I understand that if I simply do --values kafka-values.yaml when deploying the parent chart, the values will be attached to the root scope instead of the kafka scope and "kafka" subchart won't see them.
You are absolutely right that it is a possibility for you to create an extra values file to pass into your chart. So let's say you create your kafka-values.yaml file with some values. If you now install your parent chart with the option --values kafka-values.yaml, this file will now be overlayed onto the values.yaml that is inside your helm chart. You can now also use this kafka-values.yaml to do the same thing if you would like to just install the kafka chart.
In general, the order of overlaying values in helm follows the order of this list. This means that any values passed into a chart, either by external file or individual values will overlay onto the values.yaml file in the chart. If the same values are specified, the values.yaml value will be overridden. If it has not been defined in a "lower priority", the values will be overlayed into the values for the chart.
EDIT
The main difference between what you are trying to do is the fact that your kafka-values.yaml for your parent chart need to be indented under the kafka: scope.
If you have something listed as a dependency of your chart, Helm will always try to install it connected to the parent chart. It won't look for another installation elsewhere in the cluster or try to import or export values from another Helm release.
You might reasonably want to use Kafka as a messaging or eventing bus across several services. In this case you don't necessarily want Kafka tied to a single service; you could install it at the cluster level, or on dedicated hardware, or use a cloud-hosted version of it. This means you need two things: a setting to say whether or not to install Kafka as a dependency, and a setting to point to the Kafka bootstrap server(s).
# values.yaml
# kafka has settings for the Kafka broker.
kafka:
# enabled indicates whether to install Kafka as part of this release.
enabled: true
# bootstrapServers is a comma-separated list of HOST:PORT indicating
# the location of at least one known Kafka broker. Only used if
# enabled is false.
bootstrapServers: ''
In your chart requirements, you can specify a condition to cause the dependency to only be installed if the value is set:
dependencies:
- name: kafka
version: ^14
repository: https://charts.bitnami.com/bitnami
condition: kafka.enabled # <--- add this line
Finally, you need to use template logic to pass the correct Kafka address to the application.
env:
- name: KAFKA_BOOTSTRAP_SERVERS
{{- if .Values.kafka.enabled }}
value: {{ .Release.Name }}-kafka:9092
{{- else }}
value: {{ .Values.kafka.bootstrapServers }}
{{- end }}
And then when you install the chart, you can specify to use either a local or remote Kafka.
helm install chart-with-local-kafka .
# --set kafka.enabled=true # on by default
helm install chart-with-remote-kafka . \
--set kafka.enabled=false \
--set kafka.bootstrapServers=kafka.infra.example.com:9092

Helm, customicing only certain values

I want to deploy nextcloud with helm and a custom value.yaml file that fits my needs. Do i have to specify all values given from the original value.yaml or is it possible to only change the values needed, Eg if the only thing I want to change is the host adress my file can look like this:
nextlcoud:
host: 192.168.178.10
instead of copying this file and changing only a few values.
As the underlying issue was resolved by the answer of user #Kun Li, I wanted to add some examples when customizing Helm charts as well as some additional reference.
As asked in the question:
Do i have to specify all values given from the original value.yaml or is it possible to only change the values needed
In short you don't need to specify all of the values. You can change only some of them (like the host from your question).
The ways to change the values are following:
Individual parameters passed with --set (such as helm install --set foo=bar ./mychart)
A values file if passed into helm install or helm upgrade with the -f flag (helm install -f myvals.yaml ./mychart)
If this is a subchart, the values.yaml file of a parent chart
The values.yaml file in the chart
You can read more about it by following official Helm documentation:
Helm.sh: Docs: Chart template guide: Values files
A side note!
Above points are set in the order of priority. The first one (--set) will have the highest priority to override the values.
Example
A side note!
This examples assume that you are in the directory of a pulled Helm chart and you are using Helm v3
Using the nextcloud Helm chart used in the question you can set the nextcloud.host value by:
Pulling the Helm chart and editing the values.yaml
Creating additional new-values.yaml to pass it in (the values.yaml from Helm chart will be used regardless with lower priority):
$ helm install NAME . -f new-values.yaml
new-values.yaml
nextcloud:
host: 192.168.0.2
Setting the value with helm install NAME . --set nextcloud.host=192.168.0.2
You can check if the changes were done correctly by either:
$ helm template . - as pointed by user #David Maze
$ helm install NAME . --dry-run --debug
you misspelled the nextcloud to nextlcoud in your value file.

Include system username in helm charts in helm version 2.14.1

I am using helm version 2.14.1. I have created helm charts for an application that will be deployed by users to test their code on kubernetes cluster. I want to add labels for username values, so I can retrieve deployments by users (deployments by user labels). Is there a way to include system username in helm charts just like we do in Java with System.getProperty("user.name"). My helm template is like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "common.fullname" . }}--{{ Release.name }}
labels:
application: {{ include "common.name" . }}
branch: "{{ Release.name }}"
username: "{{ System.user.name }}" # need to fetch the logged in user from system here
spec:
...
Is there a standard way to achieve this or is there anyway I can allow users to input there usernames from command line while using helm install or helm template commands?
EDIT:
Although, the --set works for me in setting the values for my chart, I also need to set the same value in the dependencies. Something like this:
values.yaml
username: ""
dependency1:
username: {{ .Values.username }}
dependency2:
username: {{ .Values.username }}
...
Of course the above implementation doesn't work. I need to reference the set value in the dependencies as well
This is a community wiki answer based on the comments and posted for better visibility. Feel free to expand it.
You can use the helm template command with a --set option:
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-file stringArray set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
The --set parameters have the highest precedence among other methods of passing values into the charts. It means that by default values come from the values.yaml which can be overridden by a parent chart's values.yaml, which can in turn be overridden by a user-supplied values file, which can in turn be overridden by --set parameters.
You can check more details and examples in the official docs.
I have resolved this. Thanks for help #MichaelAlbers and #WytrzymaƂyWiktor. So the solution is as below.
helm template path/to/chart --set global.username=username
And then in all the templates refer to this value as {{ .Values.global.username }}. This works for any dependency chart as well.

Using Environment Variables with HELM

I plan to upgrade my project to HELM.
I have many environment variables that I have defined in deployment.yaml.
Best practice is it best to define the environment variables in the values.yaml file or the templates / deployment.yaml drop?
Can you help if there is a sample application you use?
Disclaimer: My answers are based on Helm 3. So let's get to it:
#1: No, in your values.yaml you define the static/default values. It's not the best approach to let static values in your template files (like deployment.yaml). To override the values of values.yaml The best practice is to use --set KEY=VALUE file. In this case, is totally possible to get the environment variable.
#2: Can you give an example? Yes, sure.
For example, I want to install Elasticsearch on my cluster using helm so I use the command:
helm install elastic/elasticsearch --version 7.8.0
But I do not want to use the default values of the chart. So I went to https://hub.helm.sh/charts/elastic/elasticsearch and https://github.com/elastic/helm-charts/blob/7.8/elasticsearch/values.yaml, saw what's possible to change, then I create the command:
helm install elastic/elasticsearch --set minimumMasterNodes=1 --set protocol=https --version 7.8.0
But in my CD tool, the minimum master nodes are different values and since this is an environment variable I changed my command line to this:
helm install elastic/elasticsearch --set minimumMasterNodes=$MIN_MASTER_NODES --set protocol=https --version 7.8.0
So, as a result, the command above will run with no problem in your CD tool once the MIN_MASTER_NODES environment variable is provided correctly.
Your use of values.yaml to define environment vars is totally up to you. Is the value static? I'd have no problem leaving it in the deployment yaml. If it's a secret you should manage it either with k8s secrets or input it when you use helm install --set-value.. If the value is dynamic and is changed often or could be changed in the future that is the true use for values.yaml imo
There's four possible places you could set environment variables, and each has a use.
Is the value essentially fixed, any time you'd run the container in any environment? For example, consider setting a Python application to not buffer its log output or specifying the container-internal port number. Set these in the image's Dockerfile:
ENV PYTHONUNBUFFERED=1
ENV PORT=8000
Is the value more or less fixed, any time you'd run the container in Kubernetes? Or, can you reliably calculate the value? In these cases, you can set the value directly in your templates/deployment.yaml file, maybe with Helm templating.
env:
- name: COORDINATOR_HOST
value: {{ .Release.Name }}-coordinator # another Service in the same chart
- name: DATABASE_DRIVER
value: postgresql # this chart doesn't support MySQL
Does the value have a sensible default, but needs to be overridden sometimes? Put it in your chart's values.yaml.
# concurrency specifies the maximum number of concurrent tasks
# to launch.
concurrency: 4
This needs to be repeated in the templates/deployment.yaml as well
env:
- name: CONCURRENCY
value: {{ quote .Values.concurrency }}
Is the value only available at deployment time; or do you need to override one of these defaults? Use the helm install -f option to provide a per-environment value
databaseHost: myapp-pg.qa.example.com
or the similar helm install --set option. If it's reasonable to include a default value, also do so as in the previous example, but if not, you can use the required template function to give a reasonable error.
env:
- name: DATABASE_HOST
value: {{ .Values.databaseHost | required "a databaseHost must be provided" }}
You can use any or all of these options, depending on the specific values, even within the same chart.
The one pattern I don't particularly recommend is giving an open-ended list of environment variables (or other raw Kubernetes YAML) in the values file. As an operator, this is hard to consume, and it especially doesn't interact well with the helm install --set option. I tend to prefer listing out each configurable option in the Helm values file, and would modify the templates/*.yaml (maybe behind a deploy-time flag) if I needed more advanced customization.