Create configmap with outside yaml files for kubernetes - kubernetes

I'm quite new for kubernetes. I am trying to create configmap with using yaml file which was user defined.
helm upgrade --install test --namespace test --create-namespace . -f xxx/user-defined.yaml
user can add any yaml file with using 'f' option.
for example;
cars.yaml
cars:
- name: Mercedes
model: E350
So command will be;
helm upgrade --install test --namespace test --create-namespace . -f xxx/cars.yaml
My question is, I want to create configmap which is name 'mercedes-configmap'
I need to read that values from cars.yaml and create automaticaly configmap with name and data of cars.yaml
Update,
I've created below configmap template;
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.cars.name }}-configmap
data:
{{- range .Files }}
{{ .Files.Get . | toYaml | quote }}
{{- end }}
The only issue that I faced, I couldnt get the whole file data.

Welcome to the community!
I have created a helm template for configmap. It works this way: you can pass configmap name - name and file name - fname where data is stored and/or it can read files from a specific folder.
Please find the template (first 3 lines are commented, it's two working implementations of logic to check values existing):
{{/*
{{ if not (or (empty .Values.name) (empty .Values.fname)) }}
*/}}
{{ if and (not (empty .Values.name)) (not (empty .Values.fname)) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.name }}-configmap
data:
{{- ( .Files.Glob .Values.fname ).AsConfig | nindent 2 }}
---
{{ end }}
{{ $currentScope := .}}
{{ range $path, $_ := .Files.Glob "userfiles/*.yaml" }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ base $path | trimSuffix ".yaml" }}-configmap
data:
{{- with $currentScope}}
{{ base $path }}: |
{{- ( .Files.Get $path ) | nindent 4 }}
{{- end }}
---
{{ end }}
First part of the template checks if configmap name and file name are set and if so, it renders it. Second part goes to userfiles directory and gets all yamls within.
You find github repo where I shared file examples and configmap.
To render the template with cars2.yaml and with/without files within userfiles directory:
helm template . --set name=cars2 --set fname=cars2.yaml
To render the same template with only files in userfiles directory:
helm template .
P.S. helm v3.5.4 was used
Useful links:
Accessing files in helm
Flow control
File path functions

Related

How to use if/else loop in Helm

I am trying to use if/else-if/else loop in helm chart. Basically, I want to add ENV configs in configfile based on the if/else condition. Below is the logic:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.applicationName }}-configmap
labels:
projectName: {{ .Values.applicationName }}
environment: {{ .Values.environment }}
type: configmap
data:
{{- if eq .Values.environment "production" }}
{{ .Files.Get "config-prod.yaml" | nindent 2}}
{{- else if eq .Values.environment "development" }}
{{ .Files.Get "config-dev.yaml" | nindent 2}}
{{- else }}
{{ .Files.Get "config-stage.yaml" | nindent 2}}
{{- end }}
But I am not getting the desired output and facing some issue. Can anybody help me out with this?
Edit1: I have added my modified configmap.yaml as per the suggestions, helm install/template command gives Error: YAML parse error on demo2/templates/configmap.yaml: error converting YAML to JSON: yaml: line 14: did not find expected key error.
also my config-prod and config-stage is being rendered (as per the condition if I give environment: production then config-prod.yaml is being added and if I give environment: stage/null then config-stage.yaml is being added.
Your question would benefit from more specifics.
Please consider adding the following to your question:
How are you trying this? What commands exactly did you run?
How are you "not getting the desired output"? What output did you get?
Please also include:
the relevant entries from your values.yaml
the config-dev.yaml and config-stage.yaml files
Have you run helm template to generate the templates that Helm would apply to your cluster? This would be a good way to diagnose the issue.
I wonder whether you're chomping too much whitespace.
And you should just chomp left, i.e. {{- .... }} rather than left+right {{- ... -}}.
Sorry guys, it was my mistake, my dev-config.yaml has envs and it was defined like key=value, instead of key: value.

trigger pod restart on configmap change

I have a configmap file defined as follows
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-dashboard-cm-conf
namespace: {{ .Release.Namespace }}
data:
{{ (tpl (.Files.Glob "conf/*").AsConfig . ) | indent 2 }}
As you can see above, it is taking up the content of the "conf" folder as a data.
Everything works fine, however the issue is observed when i am trying to implement "annotations" to trigger a "POD-restart" with the below lines in my "deployment file.
annotations:
checksum/config-map: {{ include (print .Template.BasePath "/dashboard-conf-map.yaml") . | sha256sum }}
The POD is not getting restarted, even when content of "conf" folder is changed && a "helm upgrade" is performed.
If i use a simple configmap with data defined as below, a change in parameter and "helm upgrade" does result in POD-restart
data:
parameter1: testparam1
parameter2: testparam2
I have the following question in here
Is there a way to perform checksum for the folder.
Is there a way get the output of linux-command like below in the configmap.
find dashboard/conf/ -type f -exec md5sum {} \; |md5sum
Can we perform checksum for a non-YAML file.
annotations:
checksum: {{ include (print .Template.BasePath "/logback-spring.xml") . | sha256sum }}
I get the below error
Error: YAML parse error on chart-2/charts/dashboar/templates/conf1/logback-spring.xml: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type releaseutil.SimpleHead
Can we perform checksum on file one directory above the ".Template.BasePath", i tried below combination all of them result in error.
checksum/config: {{ include (print .BasePath "../conf/values1.yaml") . | sha256sum }}
checksum/config: {{ include (print .Template.BasePath "/../../conf/values1.yaml") . | sha256sum }}
checksum/config: {{ include (print .Template.BasePath "/../conf/values1.yaml") . | sha256sum }}
error calling include: template: no template "chart-2/charts/dashboard/templates../conf/values1.yaml" associated with template "gotpl"
error calling include: template: no template "chart-2/charts/dashboard/templates/../conf/values1.yaml" associated with template "gotpl"
error calling include: template: no template "chart-2/charts/dashboard/templates/../../conf/values1.yaml" associated with template "gotpl"
The include template function is a Helm extension that executes a named template, just like the standard template directive, but returns the template's content as a string. It has nothing to do with reading files.
To read back files, you need to use the top-level .Files object. That specifically comes with a caveat that it cannot read files inside the chart's templates directory; prefixing file names with .Template.BasePath will not work, and you need to move the included files somewhere else.
Let's say you do create a subdirectory conf inside your main chart directory:
Chart.yaml
values.yaml
conf/
logback.xml
templates/
configmap.yaml
Many of the functions you list here – .Files.Get, .Files.Glob.AsConfig, tpl – return strings, so you can combine them together. For example, you can compute a checksum for the rendered content of the ConfigMap as:
annotations:
checksum/config-map: {{ (tpl (.Files.Glob "conf/*").AsConfig . ) | sha256sum }}
You could do it on a single non-YAML file if you wanted, too: .Files.Get returns a string, so
.Files.Get "conf/logback-spring.xml" | sha256sum
The root path for .Files.Get is the root of the chart. You can retrieve any file not in the templates directory, but you can't reach outside the chart.
If you want to do this with sub-chart.
kind: <ResourceKind> # Deployment, StatefulSet, etc
spec:
template:
metadata:
annotations:
checksum/config: {{ include ("mylibchart.configmap") . | sha256sum }}
Another option is https://github.com/stakater/Reloader
You can use regex to select the config based on this PR https://github.com/stakater/Reloader/pull/314

What is the difference between fullnameOverride and nameOverride in Helm?

I could find both fullnameOverride and nameOverride in Helm chart.Please help clarifying what is the difference between these two with an example.
nameOverride replaces the name of the chart in the Chart.yaml file, when this is used to construct Kubernetes object names. fullnameOverride completely replaces the generated name.
These come from the template provided by Helm for new charts. A typical object in the templates is named
name: {{ include "<CHARTNAME>.fullname" . }}
If you install a chart with a deployment with this name, and where the Chart.yaml file specifies name: chart-name...
helm install release-name ., the Deployment will be named release-name-chart-name
helm install release-name . --set nameOverride=name-override, the Deployment will be named release-name-name-override
helm install release-name . --set fullnameOverride=fullname-override, the Deployment will be named fullname-override
The generated ...fullname template is (one code branch omitted, still from the above link)
{{- define "<CHARTNAME>.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
So if fullnameOverride is provided, that completely replaces the rest of the logic in the template. Otherwise the name is constructed from the release name and the chart name, where nameOverride overrides the chart name.

Conditionally deploying a secret based on --set parameter

I have a Helm chart that I am deploying to Azure Kubernetes Service, and minikube for development purposes.
When deploying to minikube, I need to add a secret so the cluster can speak with my Azure Container Registry. This is not necessary when I'm deploying to AKS.
Is there any way I can specify whether or not to include the secret through a --set value with helm install, or do I have to set up different helm charts?
You can put anything you want inside a Go text/template conditional block, even whole Kubernetes resources.
# templates/some-secret.yaml
{{ if .Values.theSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "some.name" . }}-some-secret
labels:
{{ template "some.labels" . | indent 4 }}
data:
theSecret: {{ .Values.theSecret | b64enc }}
{{ end }}
Or, if you already have some shared Secret, you can make individual values conditional
data:
someValue: {{ .Values.someValue | b64enc }}
{{- if .Values.theSecret }}
theSecret: {{ .Values.theSecret | b64enc }}
{{- end }}
As the chart author you need to write this into the chart. If you're using a third-party chart, it's up to the chart author to provide this functionality.

How to reference a value defined in a template in a sub-chart in helm for kubernetes?

I'm starting to write helm charts for our services.
There are two things I'm not sure how they are supposed to work or what to do with them.
First: the release name. When installing a chart, you specify a name which helm uses to create a release. This release name is often referenced within a chart to properly isolate chart installs from each other? For example the postgres chart contains:
{{- define "postgresql.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
Which is then used for the service:
metadata:
name: {{ template "postgresql.fullname" . }}
It does look like "myrelease-postgresql" in the end in kubernetes.
I wonder what a good release name is? What is typically used for this? A version? Or some code-name like the ubuntu releases?
Second: referencing values.
My chart uses postgresql as a sub-chart. I'd like to not duplicate the way the value for the name of the postgresql service is created (see snipped above).
Is there a way I can reference the service name of a sub-chart or that template define {{ template "postgresql.fullname" . }} in the parent chart? I need it to pass it into my service as database host (which works if I hardcode everything but that cannot be the meaning of this).
I tried:
env:
- name: DB_HOST
value: {{ template "mychart.postgresql.fullname" . }}
But that lead into an error message:
template "mychart.postgresql.fullname" not defined
I've seen examples of Charts doing similar things, like the odoo chart. But in here that logic how the postgresql host name is created is copied and an own define in the template is created.
So is there a way to access sub-chart names? Or values or template defines?
Thanks!
Update after some digging:
According to Subcharts and Globals the templates are shared between charts.
So what I can do is this:
In my chart in _helpers.tpl I add (overwrite) the postgres block:
{{- define "postgresql.fullname" -}}
{{- $name := .Values.global.name -}}
{{- printf "%s-%s" $name "postgresql" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
So this value is used when the sub-chart is deployed. I cannot reference all values or the chart name in here as it will be different in the sub-chart - so I used a global value.
Like this I know the value of the service that is created in the sub-chart.
Not sure if this is the best way to do this :-/
Are you pulling in postgresql as a subchart of your chart (via your chart's requirements.yaml)? If so, both the postgresql (sub) chart and your chart will have the same .Release.Name - thus, you could specify your container's environment as
env:
- name: DB_HOST
value: {{ printf "%s-postgresql" .Release.Name }}
if you override postgresql's name by adding the following to your chart's values.yaml:
postgresql:
nameOverride: your-postgresql
then your container's env would be:
env:
- name: DB_HOST
value: {{ printf "%s-%s" .Release.Name .Values.postgresql.nameOverride }}
You can overwrite the values of the subchart with the values of the parent chart as described here:
https://helm.sh/docs/chart_template_guide/subcharts_and_globals/
I don't think it's possible (and it also doesn't make sense) to override the template name of the subchart.
What I would do is define the database service name in the .Values files both in the parent and sub charts and let helm override the one in the subchart - that way you will always have the database name in the parent chart. This would however mean that the service name of the database should not be {{ template "name" . }}, but something like {{ .Values.database.service.name }}
mychart/.Values
mysubchart:
service:
name: my-database
mychart/templates/deployment.yaml
env:
- name: DB_HOST
value: {{ .Values.mysubchart.service.name }}
mychart/charts/mysubchart/.Values
service:
name: my-database
mychart/charts/mysubchart/templates/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.service.name }}
Another way is to use global chart values, also described in https://helm.sh/docs/chart_template_guide/subcharts_and_globals/
For values in the helper.tpl instead of values.yaml
To access a value from a chart you do the following:
{{ template "keycloak.fullname" . }}
To access a value from a sub chart
{{ template "keycloak.fullname" .Subcharts.keycloak }}
You could import values from a sub chart as described here: https://helm.sh/docs/topics/charts/#importing-child-values-via-dependencies.
However there is a caveat. This works not for values defined at the root level in the values.yaml.
See this issue for more information: https://github.com/helm/helm/issues/9817