I have this kind of template file in helm:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: {{.Values.app.name}}-global-route
namespace: {{.Release.Namespace}}
spec:
hosts:
- "{{.Values.app.name}}-global.{{.Release.Namespace}}.svc.cluster.local"
gateways:
- {{.Values.app.name}}-gateway
- mesh
http:
# 1st priority, to route specific end-user to canary service
- route:
- destination:
host: "{{.Values.app.name}}-global.{{.Release.Namespace}}.svc.cluster.local"
subset: canary
match: {{.Values.infra.trafficRoute.canaryCondition}}
# default values supplied for templates/* files
app:
name: java-maven-app
infra:
trafficRoute:
canaryCondition:
- headers:
end-user:
exact: apratama
key:
exact: agung
So, basically what I want to achieve is to let end-user (the one who use my helm chart) customize the canary condition. The condition itself is depends on istio's match
data structure (which can be nested and complex values). I tried above with helm upgrade --install
command, but somehow I got this error:
Error: UPGRADE FAILED: YAML parse error on java-maven-app-infra/templates/global-service.yaml: error converting YAML to JSON: yaml: line 17: found unexpected ':'
make: *** [deploy-infra] Error 1
However, when I comment out this line:
match: {{.Values.infra.trafficRoute.canaryCondition}}
it works without error.
Any advice?
Solved. I chatted with some people in #helm-users slack channel (kubernetes.slack.com), and so the value being provided to the template is a string value. So one needs to convert it to yaml object and indent it approriately. I solved this by changing it slightly to this
# 1st priority, to route specific end-user to canary service
- route:
- destination:
host: "{{.Values.app.name}}-global.{{.Release.Namespace}}.svc.cluster.local"
subset: canary
match:
{{ toYaml .Values.infra.trafficRoute.canaryCondition | indent 4 }}
we discussed this solution earlier in k8s Slack. I noticed you posted your own answer, but I thought I might as well expand on it a bit in case someone else encounters the same problem.
The issue is that Helm chart templating does text templating instead of YAML templating. Therefore, the inserted YAML sub-tree (canaryCondition
) is not automatically converted to YAML and elegantly placed under the match
key, but instead it's converted to string and inserted directly where the template directive is. With simple values such as strings and integers, this works fine for most cases, but more complex values such as arrays and maps need to handled differently.
In order to insert YAML sub-trees in the template, you need to first convert the sub-tree to YAML using toYaml
function, and then ensure that correct indentation level is used with the indent
function.
{{ toYaml .Values.infra.trafficRoute.canaryCondition | indent 4 }}
See the NGINX template example for another example on how to insert YAML sub-trees in the template.
To get started in debugging Helm chart templating, you can use the helm template
command to see the YAML that the Helm chart generates.