'helm - how to loop with complex values
I need to loop over objects with range in a Helm chart.
I have error in network.yaml at line 4. How can I fix it?
My values.yaml contains:
network:
service_shob_server:
- name: shob-server-{{ .Release.Namespace }}-se
app: shob-server-{{ .Release.Namespace }}
port: 7725
targetPort: 7725
service_shob_pyland:
- name: shob-pyland-{{ .Release.Namespace }}-se
app: shob-server-{{ .Release.Namespace }}
port: 4599 #hard coded
targetPort: 4599 #hard coded
service_shob_ui:
- name: shob-ui-{{ .Release.Namespace }}-se
app: shob-ui-{{ .Release.Namespace }}
port: 7726
targetPort: 7726
service_ddsim_server:
- name: ddsim-server-{{ .Release.Namespace }}-se
app: shob-server-{{ .Release.Namespace }}
port: 4849 #hard coded
targetPort: 4849 #hard coded
service_ddsim-client:
- name: ddsim-client-{{ .Release.Namespace }}-se
app: shob-ui-{{ .Release.Namespace }}
port: 4850 #hard coded
targetPort: 4850
service_web_streamer:
- name: web-streamer-{{ .Release.Namespace }}-se
app: shob-ui-{{ .Release.Namespace }}
port: 2000
targetPort: 2000
templates/service.yaml contains:
{{- $namespace := .Release.Namespace -}}
apiVersion: v1
kind: Service
{{- range $key, $value := .Values.network }}
metadata:
name: {{ $key }}
value: {{ $value}}
namespace: {{ $namespace }}
spec:
selector:
app: {{ $key }} #shob-server-{{ $namespace }}
value: {{ $value }}
ports:
- port: {{ $key }}
value: {{ $value }}
targetPort: {{ $key }}
value: {{ $value }}
{{- end }}
---
Solution 1:[1]
In general, if you want to use Helm to produce multiple Kubernetes objects from one template file, you need to put the range loop around the entire YAML object. I'd start with the --- YAML start-of-document marker.
{{- range $key, $value := .Values.network }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ $key }}
value: {{ $value }}
{{-/* Helm will use the `helm install --namespace` by default
and you don't need to explicitly declare namespace: here */}}
spec: { ... }
{{- end }}
Your value structure is a little more complicated than it needs to be, and this is probably causing problems with the looping. In your existing structure, .Values.network is a mapping or dictionary; each of the values is a list containing a single item. I'm guessing you don't need the keys and just flattening this into a flat list would simplify things.
# modified values.yaml
network:
- name: shob-server-{{ .Release.Namespace }}-se
app: shob-server-{{ .Release.Namespace }}
port: 7725
targetPort: 7725
- name: shob-pyland-{{ .Release.Namespace }}-se
app: shob-server-{{ .Release.Namespace }}
port: 4599
targetPort: 4599
Now when you iterate over this, the special variable . will get set to each item in the list, and you can refer to fields in this .. It syntactically is the same as .Values but now . is not the top-level Helm object.
{{- range .Values.network }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ .name }}
{{- end }}
There's one more piece to this puzzle. If you run helm template over this, you'll see literal {{ .Release.Namespace }} appearing in the output. You need to use the Helm tpl function to cause Helm to evaluate the template strings from the values object. This needs the top-level Helm object, but range redefines the . special variable to be something else. I tend to save the original value of . in a variable; using $ should work as well.
{{- $top := . -}}
{{- range .Values.network }}
name: {{ tpl .name $top }}
{{- end }}
Putting this all together, you should get something like:
{{- $top := . }}
{{- range .Values.network }}
apiVersion: v1
kind: Service
metadata:
name: {{ tpl .name $top }}
spec:
selector:
app: {{ tpl .app $top }}
ports:
- port: {{ .port }}
targetPort: {{ .targetPort }}
{{- end }}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
