Exercises
Exercise 1: Creating and Using Helper Functions
In this exercise, you will create a helper function (named template) and use it to generate a Kubernetes resource.
Helper functions allow you to encapsulate common patterns and reuse them throughout your chart.
Step 2: Create a Helper Function
Navigate to the templates directory and create a new file for your helper function:
cd helper-chart\templates
New-Item -Path "_helpers.tpl" -ItemType File
Open _helpers.tpl and add a helper function that generates standard labels.
Add the following content:
{{- define "helper-chart.labels" -}}
helm.sh/chart: {{ include "helper-chart.chart" . }}
{{ include "helper-chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
This helper function creates a set of standard labels that can be reused across multiple resources.
Step 3: Create a Resource Using the Helper
Create a new template file that uses your helper function to create a ConfigMap:
New-Item -Path "configmap.yaml" -ItemType File
Open configmap.yaml and add the following content:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "helper-chart.fullname" . }}-config
labels:
{{ include "helper-chart.labels" . | indent 4 }}
data:
app.properties: |
environment={{ .Values.environment | default "development" }}
logLevel={{ .Values.logLevel | default "info" }}
This ConfigMap uses the helper-chart.labels helper function to apply consistent labels.
Step 4: Test Your Template
Use helm template to render your chart and verify that the helper function works correctly:
cd ..\..
helm template test-release ./helper-chart
Review the output to confirm that:
* The ConfigMap is created with the correct name
* The labels from your helper function are properly applied
* The labels are correctly indented in the YAML output
Step 5: Verify the Helper Function Reusability
Create another resource (for example, a Secret) that also uses the same helper function:
cd helper-chart\templates
New-Item -Path "secret.yaml" -ItemType File
Add content to secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: {{ include "helper-chart.fullname" . }}-secret
labels:
{{ include "helper-chart.labels" . | indent 4 }}
type: Opaque
data:
password: {{ .Values.password | b64enc }}
Render the chart again to see both resources using the same helper function:
cd ..\..
helm template test-release ./helper-chart
Notice how both the ConfigMap and Secret now have identical labels, demonstrating how helper functions enable consistency across resources while eliminating duplication.
Exercise 2: Using Helper Functions from Dependencies
In this exercise, you will create a new chart and add the helper chart from Exercise 1 as a dependency.
You will then use the helper function from the dependency in your new chart, demonstrating how library charts enable code reuse across multiple charts.
Step 1: Create a New Chart
Create a new Helm chart that will use the helper chart as a dependency:
cd ..\..
helm create app-chart
Step 2: Package the Helper Chart
First, package the helper chart so it can be used as a dependency.
If you are using a local file path, you can reference it directly, or package it for distribution:
helm package ./helper-chart
This creates a helper-chart-0.1.0.tgz file (assuming version 0.1.0 in Chart.yaml).
Step 3: Add the Helper Chart as a Dependency
Edit the Chart.yaml file in your app-chart directory to add the helper chart as a dependency:
cd app-chart
notepad Chart.yaml
Add a dependencies section to your Chart.yaml:
dependencies:
- name: helper-chart
version: "0.1.0"
repository: "file://../helper-chart"
If you packaged the chart, you can also reference it from a local directory or OCI registry.
Step 4: Update Dependencies
Download the dependency into your chart:
helm dependency update
This downloads the helper chart into the charts/ directory and makes its template helpers available to your chart.
Step 5: Use the Helper Function from the Dependency
Create a new resource in your app-chart that uses the helper function from the dependency:
cd templates
New-Item -Path "deployment.yaml" -ItemType File
Add content to deployment.yaml that uses the helper function from the dependency:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "app-chart.fullname" . }}
labels:
{{ include "helper-chart.labels" . | indent 4 }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "app-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
{{ include "helper-chart.labels" . | indent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
Notice that this Deployment uses helper-chart.labels from the dependency, not from the current chart.
The helper function is accessible because it is defined in a dependency.
Step 6: Test the Chart with Dependency
Render your chart to verify that the helper function from the dependency works correctly:
cd ..\..
helm template test-app ./app-chart
Review the output to confirm that:
* The Deployment is created with the correct name
* The labels from the helper-chart dependency are properly applied
* The helper function from the dependency is accessible and working
This demonstrates how library charts enable you to share helper functions across multiple charts, creating consistency and eliminating duplication at an organizational level.
Exercise 3: Type Checking and Validation
In this exercise, you will implement type checking to ensure that required values are defined and are of the correct type.
You will use Helm template functions to validate that a value is defined as a string before using it in your templates.
Step 1: Create a New Chart
Create a new Helm chart for this exercise:
cd ..\..
helm create type-check-chart
Step 2: Add Type Checking to a Template
Navigate to the templates directory and edit the deployment.yaml file:
cd type-check-chart\templates
notepad deployment.yaml
Modify the deployment to include type checking for a required string value.
Add a section that requires an environment value to be defined as a string:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "type-check-chart.fullname" . }}
labels:
{{- include "type-check-chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "type-check-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
{{- include "type-check-chart.labels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: ENVIRONMENT
value: {{ required "environment must be defined as a string" .Values.environment | typeOf | eq "string" | ternary .Values.environment (fail "environment must be a string, not " (typeOf .Values.environment)) }}
This example uses required to ensure the value exists, but we need a better approach for type checking.
Step 3: Create a Helper Function for String Type Checking
Create a helper function that validates a value is a string.
Edit or create _helpers.tpl:
notepad _helpers.tpl
Add a helper function that checks if a value is a string:
{{- define "type-check-chart.requireString" -}}
{{- if . -}}
{{- if eq (typeOf .) "string" -}}
{{- . -}}
{{- else -}}
{{- fail (printf "Value must be a string, got %s" (typeOf .)) -}}
{{- end -}}
{{- else -}}
{{- fail "Value is required and must be a string" -}}
{{- end -}}
{{- end -}}
Step 4: Use the Type Checking Helper
Update your deployment.yaml to use the helper function:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "type-check-chart.fullname" . }}
labels:
{{- include "type-check-chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "type-check-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
{{- include "type-check-chart.labels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: ENVIRONMENT
value: {{ include "type-check-chart.requireString" .Values.environment | quote }}
Step 5: Test with Valid String Value
First, test the chart with a valid string value.
Edit values.yaml:
cd ..
notepad values.yaml
Add an environment value:
environment: "production"
Render the chart to verify it works:
helm template test-release ./type-check-chart
The chart should render successfully with the environment value set to "production".
Step 6: Test Type Validation
Now test that the type checking works by providing an invalid type.
Modify values.yaml to use a non-string value:
environment: 123
Attempt to render the chart:
helm template test-release ./type-check-chart
The template should fail with an error message indicating that the value must be a string, demonstrating that your type checking is working correctly.
This exercise demonstrates how to implement type checking in Helm templates, ensuring that values meet your requirements before they are used in your Kubernetes resources.
Exercise 4: Creating Resources from Array Combinations
In this exercise, you will use nested loops to create a ConfigMap for each possible combination of two arrays.
This demonstrates how to use range to iterate over multiple arrays and generate resources dynamically.
Step 1: Create a New Chart
Create a new Helm chart for this exercise:
cd ..\..
helm create combination-chart
Step 2: Define Arrays in Values
Edit the values.yaml file to define two arrays that will be combined:
cd combination-chart
notepad values.yaml
Add two arrays to your values file:
environments:
- name: development
region: us-east-1
- name: staging
region: us-west-2
- name: production
region: eu-central-1
configurations:
- type: standard
replicas: 2
- type: high-availability
replicas: 5
This defines two arrays: environments and configurations.
We will create a ConfigMap for each combination of environment and configuration.
Step 3: Create a Template with Nested Loops
Navigate to the templates directory and create a template that generates ConfigMaps for each combination:
cd templates
New-Item -Path "configmaps.yaml" -ItemType File
Add content that uses nested range loops to create a ConfigMap for each combination:
{{- range $env := .Values.environments }}
{{- range $config := .Values.configurations }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ $.Release.Name }}-{{ $env.name }}-{{ $config.type }}-config
labels:
environment: {{ $env.name }}
region: {{ $env.region }}
config-type: {{ $config.type }}
app.kubernetes.io/name: {{ include "combination-chart.name" $ }}
app.kubernetes.io/instance: {{ $.Release.Name }}
data:
environment: {{ $env.name | quote }}
region: {{ $env.region | quote }}
config-type: {{ $config.type | quote }}
replicas: {{ $config.replicas | quote }}
{{- end }}
{{- end }}
This template uses nested range loops:
* The outer loop iterates over environments
* The inner loop iterates over configurations
* For each combination, it creates a ConfigMap with a unique name and data
Note the use of $ to access the root context when inside nested loops.
Step 4: Test the Template
Render the chart to see all the ConfigMaps that are created:
cd ..\..
helm template test-release ./combination-chart
Review the output to verify that:
* A ConfigMap is created for each combination of environment and configuration
* Each ConfigMap has a unique name combining the environment name and configuration type
* The data in each ConfigMap reflects the values from both arrays
* You should see 6 ConfigMaps total (3 environments × 2 configurations)
Step 5: Verify the Combinations
Count the ConfigMaps in the output to confirm all combinations are created:
helm template test-release ./combination-chart | Select-String -Pattern "kind: ConfigMap" | Measure-Object
You should see 6 ConfigMaps, one for each combination:
* development-standard
* development-high-availability
* staging-standard
* staging-high-availability
* production-standard
* production-high-availability
This exercise demonstrates how to use nested loops in Helm templates to generate multiple resources from array combinations, enabling you to create complex deployment scenarios efficiently.