Simplifying Kubernetes Configuration Management Using Helm
Piotr Stróż
In this tutorial, I will guide you through deploying a simple Apache web server to a Kubernetes cluster, illustrating how Helm's templating capabilities can be used to apply distinct configurations across development, staging, and production environments. This approach eliminates the need for repeated code or manually editing configuration files before applying them, making the deployment process more efficient and manageable.
Prerequisites
- A Kubernetes cluster
- Helm installed and configured
- Basic understanding of Kubernetes objects (Deployments, Services, ConfigMaps)
Overview
We will deploy an Apache web server that displays a custom message, which will vary depending on the environment (development, staging, production). We will demonstrate how Helm templating can be leveraged to manage this scenario. As we go through the example, we will gradually increase the complexity.
Step 1: Creating the Helm Chart
First, we need to create a Helm chart for our Apache web server.
Initialize Chart
Create a new Helm chart:
helm create apache-chart
This command creates a new directory apache-chart with the basic structure of a Helm chart.
Customize Chart
Remove the default templates generated by Helm:
cd apache-chart
rm -rf templates/*
Step 2: Create required Kubernetes objects
ConfigMap
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-app-config
data:
index.html: |
<html>
<head><title>App Message</title></head>
<body><h1>{{ .Values.message }}</h1></body>
</html>
Notice template directive {{ .Release.Name }} and {{ .Values.message }}.
They inject the release name and message into the ConfigMap.
Deployment
Define the Apache web server Deployment, mounting the ConfigMap with the message that will get displayed:
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web-server
labels:
version: {{ .Chart.Version }}
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-server
image: httpd
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/local/apache2/htdocs
volumes:
- name: config-volume
configMap:
name: {{ .Release.Name }}-app-config
Service
Expose the web server within the cluster via a ClusterIP service:
# templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-web-server
spec:
type: ClusterIP
selector:
app: web
ports:
- protocol: TCP
port: 80
Step 3: Create Values File
Create a values.yaml file for default values and placeholders for environment-specific configurations:
# values.yaml
message: "Welcome to our website!"
Step 4: Configuring for Different Environments
For each environment (development, staging, production), create a values file with specific configurations.
Development Environment Values
Create a values-development.yaml:
# values-development.yaml
message: "Development Environment Message"
Repeat this step for staging and production environments, customizing the message and namespace as necessary.
Step 5: Deploying to Your Cluster
First create a development namespace:
kubectl create namespace development
Next deploy the chart to the development namespace using Helm:
helm install apache-dev ./apache-chart -f ./apache-chart/values-development.yaml --namespace development
Repeat for staging and production by using their respective values files.
Advanced Helm Templating Features
To take full advantage of Helm's templating capabilities, consider incorporating the following features:
Conditional Template Logic
Use conditional logic to include or exclude resources based on values:
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web-server
labels:
version: {{ .Chart.Version }}
spec:
replicas: {{ .Values.replicaCount | default 1 }} # <- conditionals
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-server
image: httpd
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/local/apache2/htdocs
volumes:
- name: config-volume
configMap:
name: {{ .Release.Name }}-app-config
Using Helm Functions
Utilize Helm functions to manipulate strings, lists, and other data types:
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web-server
labels:
app: {{ .Chart.Name }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: {{ required "image.repository is required" .Values.image.repository }}:{{ .Values.image.tag | default "latest" | quote }}
ports:
- containerPort: 80
resources:
limits:
cpu: {{ .Values.resources.limits.cpu | default "0.5" | quote }}
memory: {{ .Values.resources.limits.memory | default "512Mi" | quote }}
volumeMounts:
- name: config-volume
mountPath: /usr/local/apache2/htdocs
volumes:
- name: config-volume
configMap:
name: {{ .Release.Name }}-app-config
Using Templates
Break down complex charts into smaller, reusable templates or subcharts for better manageability and reusability:
# templates/_helpers.tpl
{{- define "apache-chart.fullname" -}}
{{- .Release.Name }}-{{ .Chart.Name }}
{{- end -}}
Configuring Helm Hooks
Use Helm hooks to manage pre-install, post-install, and other lifecycle events for your Helm releases:
# templates/job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-pre-install-job"
annotations:
"helm.sh/hook": pre-install
spec:
template:
spec:
containers:
- name: pre-install-job
image: busybox
command: ["sh", "-c", "echo Hello, Helm!"]
restartPolicy: Never
Conclusion
This tutorial demonstrated how to use Helm's templating engine and values files to manage configurations for Kubernetes applications across multiple environments. By leveraging advanced Helm features such as conditional logic, functions, templates, subcharts, and hooks, you can create flexible and maintainable Helm charts for complex application deployments.