Helm simple for loop - kubernetes-helm

I can not find a way to just iterate over a simple range, 10 -> 20 using helm templating.
{{range 10 until 20 }}
- port: {{ . }}
targetPort: {{ . }}
protocol: TCP
name: brick-{{ . }}
{{end}}

Helm uses the standard Go text/template system for rendering templates, plus (most of) the Sprig extension library, plus a couple more things. In particular, Sprig includes until and untilStep functions to generate lists of numbers, which you can then range over. So you should be able to:
{{- range untilStep 10 20 1 }}
- port: {{ . }}
...
{{- end }}

Related

Merging two Dictionaries in Helm

I am using Helm 3. I have two values.yaml files. In common/values.yaml I have defined:
deployment:
ports:
- name: http
protocol: TCP
The common is of the type library. In my-app, which is of the type application, the common is added as a dependency. In my-app/values.yaml I have added:
deployment:
ports:
- containerPort: 8081
I have defined a template _deployment.yaml in common/templates. In this file I am trying to merge these two deployment dictionaries into one by using:
{{- $deployment := merge .Values.common.deployment .Values.deployment -}}
When I am printing {{ $deployment }}, it is giving output:
map[ports:[map[containerPort:8080 name:http protocol:TCP]]]
And if I do:
{{- $deployment := merge .Values.deployment .Values.common.deployment -}}
The output of {{ $deployment }} is:
map[ports:[map[containerPort:8081]]]
Moreover the output of {{ .Values.common.deployment }} is:
map[ports:[map[name:http protocol:TCP]]]
And the output of {{ .Values.deployment }} is:
map[ports:[map[containerPort:8081]]]
What I would like to have after merging is:
deployment:
ports:
- name: http
protocol: TCP
containerPort: 8081
Any advice you could give would be much appreciated.
Looks like the merge operation does not work as expected on lists (it's a common problem, as the merge operation is ambiguous on list: should a list be appended or replaced when merging ?)
Anyway, I would suggest to merge the ports data with:
{{- $ports := merge .Values.deployment.ports[0] .Values.common.deployment.ports[0] -}}
and render the result with:
deployment:
ports:
- {{- toJson $ports }}
HTH

Testing the existence of helm element defined in values.yaml

I am new in helm and currently come up with a situation where I need to test the existence of 2 parameters defined in values.yaml and if present, use the value of the same in sample.yaml.
Note - This is sure that one of them will be present.
For example:
I am testing for these 2 values:
1 - {{ .Values.probes.xyz.readiness.initialDelaySeconds }}
2 - {{ .Values.readiness.xyz.initialDelaySeconds }}
And inside sample.yaml, I have to implement one of the above parameter based on existence:
initialDelaySeconds: <one of the above values needs to be implemented based on the existence>
I understand it's a simple if else condition, but I am unable to implement.
Any help would be appreciated.
For logic where you want to use some value if it's set and some other value if not, the Helm default function is usually a good match.
{{- $v1 := .Values.probes.xyz.readiness.initialDelaySeconds }}
{{- $v2 := .Values.readiness.xyz.initialDelaySeconds }}
initialDelaySeconds: {{ $v1 | default $v2 }}
If you have multiple settings like this, you can also do things like merge the two values-item dictionaries together.
{{- $readiness := merge dict .Values.probes.xyz.readiness .Values.readiness.xyz }}
initialDelaySeconds: {{ $readiness.initialDelaySeconds }}
{{- if .Values.probes.xyz.readiness.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.probes.xyz.readiness.initialDelaySeconds }}
{{ else if .Values.readiness.xyz.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.readiness.xyz.initialDelaySeconds }}
{{- end }}
helm Flow control

Helm include only existing named template

I'm using Helm for to deploy multiple K8s deployments. In some deployments I need to include extra environment variables, but for the majority of deployment the standard env. variables are enough. I would like to have named template for those deployments that must have extra env. variables.
Can I include a named template only if the named template exist?
Something like this:
{{ range $idx, $svc := .Values.services }}
kind: Deployment
metadata:
name: {{ $svc.name }}
spec:
containers:
- name: {{ $svc.name }}
env:
- name: JAVA_OPTS
- value: {{ $svc.javaOpts }}
# if template_exists (print $svc.name "-env")
{{ include (print $svc.name "-env") . | indent 12 }}
# end
{{- end -}}
It's in pseudo-code. How to do the # if part?
Thank you.
The easiest way would be to add additional key like templateExists: true to your services and check it with a simple if statement in your deployment:
{{- if $svc.templateExists }}
{{ include (print $svc.name "-env") . | indent 8 }}
{{- end -}}
services:
svc1:
templateExists: true
name: svc1
javaOpts: "-Xms128m -Xmx512m"
svc2:
name: svc2
javaOpts: "-Xms256m -Xmx512m"
Here is a solution that I came up now. I check if there are any files in the chart that matches the pattern [service]-env.yaml and if there are then I include the content of that file in the deployment.
{{- range $path, $_ := $f.Glob "**-env.yaml" }}
{{- if contains $svc.app.name $path }}
{{ $f.Get $path | indent 8 }}
{{- end }}
{{- end }}
That way, for services that require extra env. variables we can include a file in files/service-env.yaml and those variables will be added to the deployment. For services that do not require such variables, it's left empty.

Kubernetes multiple environment variables per environment using Helm 3 go template

I have 2 different values.yaml files per stage and production environment such as values.dev.yaml > values.prod.yaml and using with Helm 3. I would like to learn the best practices how to pass environment variables per environments.For instance we need to set different parameters to NODE_ENV variable.
-Should I specify the variable as hard coded as below and pass the environment variables when running helm upgrade/install command with --set flag?
-What is the correct way to use go template to do this. Can we specify something {{ .Values.node_env.value}} and then pass this env value in values yaml and use only -f values.yaml flag?
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
- name: "NODE_ENV"
value: "stage"
- name: "NODE_ENV"
value: "production"
If you have one value file per environment (it is not clear to me this is your case.) like values.prod.yaml (for prod) and values.dev.yaml (for dev), then your templeate can look like this.
This will cause the template to look for extraEnv: in your values{dev/prod}.yaml and iterate over all key/values from that section.
env:
{{- range $key, $value := .Values.extraEnv }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
In your values.dev.yaml files you add all your KEY: values that are specific for this environment. Note you can have multiple key values here, all of them will be loaded. In this case we have NODE_ENV, ANOTHER_KEY, YET_ANOTHER_KEY - all of them will be loaded.
extraEnv:
NODE_ENV: stage
ANOTHER_KEY: value
YET_ANOTHER_KEY: value
same in your values.prod.yaml multiple KEY: value pairs can be specified and all of them will be loaded.
extraEnv:
NODE_ENV: production
ANOTHER_KEY: value

Unable to define range of values for ports

My goal is to have multiple ports defined for a service of type LoadBalancer and I do not want to copy paste the same thing over and over again.
I did come to a solution, but sure how I could define the range - I need all values from 50000 to 50999.
In my service, I define the range:
{{- range $service.ports }}
- name: tport
protocol: TCP
port: {{ . }}
{{- end }}
And in my values file:
ports:
- 50000
- 50001
- 50999
How could I define the ports or update the service template to do this?
Put the min and max port as two different values on your values.yaml and use the range on your template like this:
{{- range untilStep (.Values.config.min_port|int) (.Values.config.max_port|int) 1 }}
- port: {{ . }}
targetPort: "tcp-{{ . }}"
protocol: TCP
name: "tcp-{{ . }}"
{{ -end }}