Create a Custom Helm Template

Shashwot Risal
7 min readFeb 18, 2022
Kubernetes using Helm Chart

Introduction
Helm is a Kubernetes package manager that makes packaging, configuring, and deploying apps and services to Kubernetes clusters quick and easy. Helm charts are one of the best practices for building efficient clusters in Kubernetes. It contains the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Helm charts install apps using a template-based technique. Templates provide projects structure and may be used for any sort of project.

What is a Helm Chart ?
Charts are Kubernetes resource bundles. A Helm chart is a collection of files contained within a directory. The chart’s name is the directory name (without the versioning information). Helm charts are made up of a yaml self-descriptor file and one or more Kubernetes manifest files known as templates. In a structured fashion, the YAML file describes the default configuration data for the templates. The Go template language is used to create Helm Chart templates.

How to Create a Helm Chart ?
In order to create a Helm chart, you must first create the chart itself, then configure the image pull policy, and then define extra information in the values.yaml file.

Let us install helm first with the following commands:

  1. Install Helm
    ( With this current document I am using version 3.8.0 )
$ wget https://get.helm.sh/helm-v3.8.0-linux-amd64.tar.gz
$ tar -xvzf helm-v3.8.0-linux-amd64.tar.gz
$ mv linux-amd64/helm /usr/local/bin/helm

2. Create Helm Chart
Now we will create the helm chart with the help of helm binary.

$ helm create test

The Helm chart directory contains:
charts — Used for adding dependent charts. Empty by default.
templates — Configuration files that is deploy in the cluster.
chart.yaml — Outline of the Helm chart structure.
values.yaml — Formatting information for configuring the chart.

Configuring Helm Chart
Open the values.yaml file in a text editor. This will give you the basic idea of what are configurable in the values file. Locate the image values. This is the place where you define your container images.

  • repository: is the name of the image that you want to run.
  • tag: is the version of the image
  • pullPolicy: has three possible values:-
    1. IfNotPresent: Downloads a new version of the image if one does not exist in the cluster
    2. Always: Pull the image on every restart of deployment.
    3. Latest: Pull the most up-to-date version available.

Lets change the value of the images so that we can use our custom image in the helm chart. In my case I changed the value to the following:

image:
repository: shashwot/nginx-more
pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion.
tag: “latest”

Read More On : Helm — Values

Charts.yaml
Chart.yaml contains metadata about the chart itself: its name, the chart version, a description, and similar details. In Helm 3 it can contain dependencies as well.

Read More On : Helm — Charts

Templates
_helpers.tpl
Files whose name begins with an underscore (_) are assumed to not have a manifest inside. These files are not rendered to Kubernetes object definitions, but are available everywhere within other chart templates for use. These files are used to store partials and helpers. When we first created test chart, we saw a file called _helpers.tpl. That file is the default location for template partials.

Read More On : Helm — Templates

Secrets and ConfigMaps Templates
Now that we know what a Helm chart is, lets create a new template of our own. Since the default Helm Chart does not create a configmap and a secrets on it’s own, lets create one so that our deployment takes the values during runtime.

configmap.yaml

{{- if .Values.configmap.enabled -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "test.fullname" . }}
labels:
{{- include "test.labels" . | nindent 4 }}
data:
{{- range $name, $config := .Values.configmap.values }}
{{ $name }}: {{ $config | quote }}
{{- end }}
{{- end }}

Explanation:

{{- if .Values.configmap.enabled -}} : This will check if the configmap is enabled in the values.yaml file. It takes two values. true or false. If the value is true, configmap will be used, If the value is false, configmap will not be used in the deployment.
{{ include “test.fullname” . }} : This will include the .full name of the chart. It is defined in _helpers.tpl file and will override this value when you apply the chart.
{{- range $name, $config := .Values.configmap.values }} : This will iterate over the values.yaml file under configmap’s value.

secrets.yaml

{{- if .Values.secrets.enabled -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "test.fullname" . }}
labels:
{{- include "test.labels" . | nindent 4 }}
type: Opaque
data:
{{- range $name, $config := .Values.secrets.values }}
{{ $name }}: {{ $config | b64enc | quote }}
{{- end }}
{{- end }}

Explanation:

{{- if .Values.secrets.enabled -}} : This will check if the secret is enabled in the values.yaml file. It takes two values. true or false. If the value is true, secrets will be used, If the value is false, secrets will not be used in the deployment.
{{ include “test.fullname” . }} : This will include the .full name of the chart. It is defined in _helpers.tpl file and will override this value when you apply the chart.
{{- range $name, $config := .Values.secrets.values }} : This will iterate over the values.yaml file under secret’s value.
b64enc is the encoding done for the secrets.

Use the Secrets and Configmaps in Deployment
In order for the configmap and secret to be mounted to the deployment file, we need to change the template for the deployment as well. So, let edit the deployment.yaml file.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "test.fullname" . }}
labels:
{{- include "test.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "test.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "test.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "test.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if and .Values.configmap.enabled .Values.secrets.enabled }}
envFrom:
- configMapRef:
name: {{ include "test.fullname" . }}
- secretRef:
name: {{ include "test.fullname" . }}
{{- else if .Values.configmap.enabled }}
envFrom:
- configMapRef:
name: {{ include "test.fullname" . }}
{{- else if .Values.secrets.enabled }}
envFrom:
- secretRef:
name: {{ include "test.fullname" . }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

If you check the deployment file you can see that we have added the secretRef and configMapRef in the envFrom.
Explanation:

  • {{- if and .Values.configmap.enabled .Values.secrets.enabled }} : This will check the if condition if the values in configmap and secrets are enabled.
  • {{- else if .Values.configmap.enabled }} : Will check for the condition if the above fails and only configmap is enabled.
  • {{- else if .Values.secrets.enabled }} : If both are false and secrets is only enabled then the condition for secrets only will get executed.
  • Finally if all the conditions are false, non of the condition will be executed.

Update the values.yaml file
Now that we have created a template, we need to use those values in the values.yaml file which would look something like this. Use the name and config as per your need. For now I have used redis host and port for the configmap and the secrets as redis password.

configmap:
enabled: true
values:
REDIS_HOST: redis
REDIS_PORT: 6379
secrets:
enabled: true
values:
REDIS_PASS: redis@1234

DEBUG
We have our templates ready with configmap and secrets, we need to apply the helm templates in our kubernetes cluster. But first, lets us check that the configuration we wrote are all correct and working. In order to do so, helm can--debug and--dry-run the template for us and give us the visualization of the yaml files.
Inside the folder test, run the following command. Here test is the name of the deployment that you want to pass as a deployment name.

$ helm install --dry-run --debug test .

You will find output similar to this.

install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/linux/helm-docs/test
NAME: test
LAST DEPLOYED: Fri Feb 18 07:14:17 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}




---
# Source: test/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: test
labels:
helm.sh/chart: test-0.1.0
app.kubernetes.io/name: test
app.kubernetes.io/instance: test
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
type: Opaque
data:
REDIS_PASS: "cmVkaXNAMTIzNA=="
---
# Source: test/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
labels:
helm.sh/chart: test-0.1.0
app.kubernetes.io/name: test
app.kubernetes.io/instance: test
app.kubernetes.io/version: "1.16.0"
app.kubernetes.io/managed-by: Helm
data:
REDIS_HOST: "redis"
REDIS_PORT: "6379"

Also check that the envFrom value has been activated in the deployment yaml.

envFrom:
- configMapRef:
name: test
- secretRef:
name: test

RUN
For the helm chart to run, we need to remove the debug and use upgrade which will upgrade any changes in the template values and apply the configs.

$ helm upgrade --install test .

CONCLUSION
In this way we have created our first custom helm template with configmaps and secrets and used them in the deployment template. This is the very first of configuring the templates and you can edit the files as per your need. I hope this article can help you to further manage your kubernetes yaml file using Helm.
Happy Helming!

REFERENCES
https://github.com/shashwot/helm-template

--

--