Hi i need to make these Options changeabel:
values.yaml
connector:
proxyname: "xx.${{ .Values.context }}.xx.xx"
ingress:
hosts:
- host: xx.${{ .Values.context }}.xx.xx
tls:
hosts:
- xx.${{ .Values.context }}.xx.xx
my understanding was i can call it now like this:
helm install newpod -f ... --set context=${{ github.event.inputs.context }} .
But after i call this i get the following message:
.... [spec.rules[0].host: Invalid value: "xx.{{ .Values.context }}.xx.xx" ....
how can i deal with it?
This can be achieved using tpl function
values.yaml
context: test
connector:
proxyname: "xx.{{ .Values.context }}.xx.xx"
manifest.yaml
test: {{ tpl .Values.connector.proxyname . }}
If you need to use them in your ingress inside a range, use $ to point to the root context
ingress.yaml
...
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ tpl . $ | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ tpl .host $ | quote }}
http:
paths:
...
NOTES.txt
...
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ tpl $host.host $ }}{{ . }}
...
Related
I have the following values.yaml
ingresses:
- name: public
class: "nginx"
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 122m
nginx.ingress.kubernetes.io/proxy-connect-timeout: "7"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
labels: {}
rules:
- host: example.com
http:
paths:
- path: /asd/as
pathType: ImplementationSpecific
backend:
service:
name: one
port:
number: 8080
- backend:
service:
name: log
port:
number: 8081
path: /path/log
pathType: ImplementationSpecific
- backend:
service:
name: got
port:
number: 8082
path: /api/got
pathType: ImplementationSpecific
tls:
- hosts:
- example.com
secretName: cert
- name: public
annotations:
labels: {}
rules:
- host: example1.com
http:
paths:
- backend:
service:
name: web
port:
number: 8090
pathType: ImplementationSpecific
tls:
- hosts:
- example1.com
secretName: qwe
and I have the following ingress file:
{{- $top := . -}}
{{- range $ingress := .Values.ingresses }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $ingress.name }}
namespace: {{ $ingress.namespace }}
{{- with $ingress.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- if and $ingress.class (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ $ingress.class }}
{{- end }}
{{- if $ingress.tls }}
tls:
{{- range $ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range $ingress.rules }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
{{- if and .path (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
- path: {{ .path }}
{{ end }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
service:
name: {{ .backend.service.name }}
port:
number: {{ .backend.service.port.number}}
{{- end }}
{{- end }}
{{- end }}
This only generates one ingress (whichever is the last one in values files). I tried using range $ingress := .Values.ingress but it keeps giving me an error whenever I try $ingress.name . What changes do I make to the ingress.yaml to be able to deploy both these ingresses.
Edit: Made edits based on David's answer.
You need to break the two separate ingress configurations up in the Helm values somehow. Right now they're in a single map object under ingress:, so .Values.ingress.name for example only has one value rather than being something you can iterate over.
A YAML list here makes sense:
# values.yaml
ingresses:
- name: example-com
class: nginx
rules: [...]
- name: example1-com
class: nginx
rules: [...]
Then you can iterate over this list with a range loop. The important thing to know about a range loop is that it rebinds the . special variable, which is the base of constructs like .Values; that means that you need to save the original value of . outside the loop (the $ special variable may work as well). You can generate multiple Kubernetes objects in a single Helm template file so long as each begins with the YAML --- start-of-document marker (and it's valid to generate no output at all).
{{-/* save the original value of . */-}}
{{- $top := . -}}
{{-/* iterate over the ingress configurations */-}}
{{- range $ingress := .Values.ingresses }}
---
{{-/* your existing conditionals can go here, simplifying */}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{-/* this comes from the per-ingress config */}}
{{- with $ingress.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
{{-/* if you need to use "standard" helper functions, make sure
to pass the saved $top value as their parameter */}}
name: {{ include "mychart.fullname $top }}-{{ $ingress.name }}
spec: { ... }
{{- end }}
You also may want to reconsider how much of this is appropriate to include in arbitrarily-configurable values. Rather than essentially write out the entire Ingress object in Helm values, you may find it easier to write out things like the path mappings in the template files themselves, and have a few high-level controls ("enabled", "host name", "TLS secret name") exposed. Things like the backend service name and port will correspond to other things in your chart and you may need to compute the service name; someone just installing your chart shouldn't need to configure this.
I am defining a PrometheusRule as follow:
prometheusRule:
rules:
- alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 10
for: 0m
labels:
severity: warning
annotations:
summary: Blackbox SSL certificate will expire soon (instance {{ $labels.instance }})
description: "SSL certificate expires in 30 days\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
And the template yml from helm chart:
{{- if .Values.prometheusRule.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: {{ template "prometheus-blackbox-exporter.fullname" . }}
{{- with .Values.prometheusRule.namespace }}
namespace: {{ . }}
{{- end }}
labels:
{{- include "prometheus-blackbox-exporter.labels" . | nindent 4 }}
{{- with .Values.prometheusRule.additionalLabels -}}
{{- toYaml . | nindent 4 -}}
{{- end }}
spec:
{{- with .Values.prometheusRule.rules }}
groups:
- name: {{ template "prometheus-blackbox-exporter.name" $ }}
rules: {{ tpl (toYaml .) $ | nindent 8 }}
{{- end }}
{{- end }}
when I run helm template, tpl func it is not resolving the $labels and $values vars. When I remove annotations then the helm template is not complaining anymore. Where do fail?
error:
Error: template: prometheus-blackbox-exporter/templates/prometheusrule.yaml:18:16: executing "prometheus-blackbox-exporter/templates/prometheusrule.yaml" at <tpl (toYaml .) $>: error calling tpl: error during tpl function execution for "- alert: SSLCertExpiringSoon\n annotations:\n summary: Blackbox SSL certificate will expire soon (instance {{ $labels.instance\n }})\n expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 10\n for: 0m\n labels:\n release: prometheus\n severity: warning\n- alert: SSLCertExpiringSoon\n annotations: null\n expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 3\n for: 0m\n labels:\n severity: critical": parse error at (prometheus-blackbox-exporter/templates/prometheusrule.yaml:3): undefined variable "$labels"
Prometheus's alerting rules also use {{ ... $variable ... }} syntax, similar to Helm but with a different variant on the Go text/template syntax. When you pass this file through tpl, Helm tries to evaluate the embedded {{ ... }} template and evaluate any blocks there. Since $labels and $value aren't local variables defined at the Helm level, you get this error.
If you just want Prometheus to see this file as-is, and you don't need to replace anything at the Helm level (the file doesn't include references to .Values) then you don't need tpl
rules: {{ toYaml . | nindent 8 }}
If you do need tpl, then inside the included file you need to cause {{ to be emitted as a string and not processed as a template. One syntactic approach to it is to create a template block that prints out {{:
description: "VALUE = {{ "{{" }} $value }}"
# ^^^^^^^^^^ a {{ ... }} block that prints "{{"
The working version of syntax is as follow:
{{ `{{` }} $value }}
I am very new to using helm charts and not sure why I get this error when I try to install my helm chart. I am using --set with helm install command to set the hostname at ingress.hosts[0].host.I do not understand why it says missing paths where as "paths" is already present.
ingress.yaml
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "project.fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app.kubernetes.io/name: {{ include "project.name" . }}
helm.sh/chart: {{ include "project.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
{{- end }}
values.yaml
...
...
...
ingress:
enabled: true
hostname: some_hostname
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "180"
nginx.ingress.kubernetes.io/proxy-send-timeout: "180"
nginx.ingress.kubernetes.io/proxy-read-timeout: "180"
hosts:
- host: some_hostname
paths: [/]
tls:
- secretName: some_secretname
hosts:
- some_hostname
resources: {}
...
...
...
command to install helm
helm upgrade --install $(PROJECT_NAME) --set ingress.hosts[0].host="${HOST_NAME} --set ingress.tls[0].hosts="{${HOST_NAME}}""
error:
Error: UPGRADE FAILED: error validating "": error validating data: ValidationError(Ingress.spec.rules[0].http): missing required field "paths" in io.k8s.api.extensions.v1beta1.HTTPIngressRuleValue
I had the same issue, for some reason if you define the host in the --set you also have to define the path in the set (even though it matches the yaml). Like so,
helm upgrade --install $(PROJECT_NAME) --set ingress.hosts[0].host=${HOST_NAME} --set ingress.hosts[0].paths[0]=/
I haven't done tls yet so I am not sure if that has the same issue.
I have the following ingress.yaml:
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host }} // row 31
http:
paths:
{{- range .paths }}
- path: {{ . | quote }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
And the following values to feed this template:
hosts:
host: "app.example.com"
paths:
- "/api"
- "/oauth"
tls:
- secretName: "example-tls"
hosts:
- "*.app.example.com"
- "dev.example.com"
When I run "helm install" it fails on:
Error: UPGRADE FAILED: template: templates/ingress.yaml:31:15:
executing "templates/ingress.yaml" at <.host>: can't evaluate field
host in type interface {}
So for me it looks like hosts must be a list, not a dictionary (because of range instruction). So I convert it:
hosts:
- host: "app.example.com"
paths:
- "/api"
- "/oauth"
But in this case I get:
warning: destination for hosts is a table. Ignoring non-table value
[map[host:app.example.com paths:[/api /oauth]]]
and the same error as above in addition.
How to make it working?
UPDATE 1
Values:
ingress:
enabled: true
rules:
- host: c1.app.example.com
paths:
- /api
- /oauth
- host: c2.app.example.com
paths:
- /api
- /oauth
tls:
- secretName: "example-tls"
hosts:
- "*.app.example.com"
- "dev.example.com"
Template:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.rules }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . | quote }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
UPDATE 2
I understood that problem was not in code but in command line. I fed with string instead of array.
helm template ... --set ingress.hosts.host=c1.app.example.com ...
I will try to figure out how to provide multiple values and update it here.
UPDATE 3
I erased data from values:
ingress:
enabled: false
rules:
- host:
tls:
- secretName:
hosts: []
The template is looking for .Values.ingress.hosts, whereas in your displayed values there is no ingress prefix. And as range operator is being used, we should have a list of dictionary.
Also, before doing a helm install, it would be good to run helm template just to make sure the the YAML definitions are rendered correctly.
Considering the below content in values.yaml:
---
ingress:
hosts:
-
host: app1.example.com
paths:
- /api
- /oauth
-
host: app2.example.com
paths:
- /api1
- /authz
tls:
- hosts:
- "*.app.example.com"
- "dev.example.com"
secretName: "example-tls"
Running helm template command results in (I have defined serviceName as haproxy, and servicePort as 8080 for illustration):
spec:
tls:
- hosts:
- "*.app.example.com"
- "dev.example.com"
secretName: example-tls
rules:
- host: app1.example.com // row 31
http:
paths:
- path: "/api"
backend:
serviceName: haproxy
servicePort: 8080
- path: "/oauth"
backend:
serviceName: haproxy
servicePort: 8080
- host: app2.example.com // row 31
# similar output for app2.example.com
Answering my own question.
The problem was in mismatch of ingress template structure and command line arguments that I have provided for params override.
This is the proper fit of command line arguments:
helm upgrade <some other options here>
--values ./values.yaml
--set ingress.enabled=True
--set ingress.tls[0].hosts[0]=app.example.com
--set ingress.tls[0].secretName=example-tls
--set ingress.rules[0].host=app.example.com
That populates values.yaml:
ingress:
enabled: false
rules:
- host:
tls:
- secretName:
hosts: []
For ingress template:
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- secretName: {{ .secretName }}
hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.rules }}
- host: {{ .host | quote }}
http:
paths:
- path: /api
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
I am installing a helm chart which has a ingress.yaml template.
I get this error:
Error: render error in "chartmuseum/templates/ingress.yaml": template: chartmuseum/templates/ingress.yaml:35:22: executing "chartmuseum/templates/ingress.yaml" at <.Values.service.servicename>: nil pointer evaluating interface {}.service
I am not able to find where the problem is. The same set of if else structure works abolutely fine in the service.yaml of the same helm chart.
- path: {{ default "/" .path | quote }}
backend:
{{- if .Values.service.servicename }}
serviceName: {{ .Values.service.servicename }}
{{- else }}
serviceName: {{ include "chartmuseum.fullname" . }}
{{- end }}
Getting error on this line --> serviceName: {{ .Values.service.servicename }}
The code that works in service.yaml fine is
metadata:
{{- if .Values.service.servicename }}
name: {{ .Values.service.servicename }}
{{- else }}
name: {{ include "chartmuseum.fullname" . }}
{{- end }}
Expected result: if there is a servcice.servicename in values in values.yaml file , the ingress should pick the value from there for the key serviceName. Else it should include "chartmuseum.fullname".
The same structure works fine for service.yaml.
Below is the url of the original helm chart that i am using.
https://github.com/helm/charts/tree/master/stable/chartmuseum
I just modified the ingress.yaml to add if else block around line 31.
Ingress.yaml https://github.com/helm/charts/blob/master/stable/chartmuseum/templates/ingress.yaml
Values.yaml file is insignificant. I have the below values in it
service:
servicename: helm-charts-test
but even without this value, the if else block is expected to work.
What you're seeing is a weird caveat in Go templating. Your conditional logic is being evaluated inside a range loop. This means . you're using to access Values is not the one you expect it to be, as it's overridden for each range iteration evaluation.
You can use $, which references the global scope in order to access the Values as expected.
For your scenario, it would be something like:
- path: {{ default "/" .path | quote }}
backend:
{{- if $.Values.service.servicename }}
serviceName: {{ $.Values.service.servicename }}
{{- else }}
serviceName: {{ include "chartmuseum.fullname" $ }}
{{- end }}
See here for more details.
I followed this answer by #Torrey and replaced
targetPort: {{ .Values.non_existing.port | default 1234 }}
with
targetPort: {{ (.Values.non_existing).port | default 1234 }}
and it worked