Exercises and Projects
1 - Hands-on exercises
Exercise 1: Installation and configuration
Objective: Install a chart from a public repository.
# Tâches :
# 1. Ajouter le repository Bitnami
# 2. Rechercher le chart nginx
# 3. Voir les valeurs disponibles
# 4. Installer avec 3 réplicas et un service NodePort
# 5. Vérifier le déploiement
Solution
# 1. Ajouter le repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 2. Rechercher nginx
helm search repo nginx
# 3. Voir les valeurs
helm show values bitnami/nginx > nginx-values.yaml
# 4. Installer
helm install my-nginx bitnami/nginx \
--set replicaCount=3 \
--set service.type=NodePort
# 5. Vérifier
helm list
kubectl get pods,svc
Exercise 2: Create a basic chart
Objective: Create a chart for a simple application.
# Tâches :
# 1. Créer un nouveau chart "hello-world"
# 2. Modifier pour déployer l'image hashicorp/http-echo
# 3. Configurer le message via values
# 4. Installer et tester
Solution
# 1. Créer le chart
helm create hello-world
# 2-3. Modifier values.yaml
# values.yaml
replicaCount: 1
image:
repository: hashicorp/http-echo
tag: "0.2.3"
pullPolicy: IfNotPresent
message: "Hello from Helm!"
service:
type: ClusterIP
port: 5678
# templates/deployment.yaml (extrait)
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
args:
- "-text={{ .Values.message }}"
ports:
- containerPort: 5678
# 4. Installer et tester
helm install hello ./hello-world
kubectl port-forward svc/hello-hello-world 8080:5678
curl localhost:8080
Exercise 3: Advanced templates
Objective: Use the templating functions.
Create a template that:
- Generates standard labels
- Configures resources conditionally
- Iterates over a list of hosts for the Ingress
Solution
# _helpers.tpl
{{- define "app.labels" -}}
app.kubernetes.io/name: {{ include "app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
{{- end }}
# deployment.yaml
metadata:
labels:
{{- include "app.labels" . | nindent 4 }}
spec:
template:
spec:
containers:
- name: app
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 10 }}
{{- end }}
# ingress.yaml
{{- if .Values.ingress.enabled }}
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ $.Release.Name }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
Exercise 4: Release management
Objective: Practice the release lifecycle.
# Tâches :
# 1. Installer une release
# 2. Faire un upgrade avec nouvelles values
# 3. Voir l'historique
# 4. Faire un rollback
# 5. Désinstaller proprement
Solution
# 1. Installer
helm install myapp bitnami/nginx --set replicaCount=1
# 2. Upgrade
helm upgrade myapp bitnami/nginx --set replicaCount=3 --set service.type=LoadBalancer
# 3. Historique
helm history myapp
# 4. Rollback
helm rollback myapp 1
# 5. Désinstaller
helm uninstall myapp
Exercise 5: Hooks and Tests
Objective: Create a pre-install hook and a test.
Solution
# templates/hooks/pre-install.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-init"
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
containers:
- name: init
image: busybox
command: ['sh', '-c', 'echo "Initializing..."']
restartPolicy: Never
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-test"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test
image: busybox
command: ['wget', '-q', '-O-', '{{ include "app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
# Tester
helm test myapp
2 - Complete project: Web Application
Description
Create a complete Helm chart for a web application with:
- Frontend (Nginx with custom configuration)
- Backend API (custom image or http-echo)
- PostgreSQL database (dependency)
- Redis cache (dependency)
- Ingress with TLS
Chart structure
webapp-chart/
├── Chart.yaml
├── values.yaml
├── values-production.yaml
├── templates/
│ ├── _helpers.tpl
│ ├── frontend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── configmap.yaml
│ ├── backend/
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ ├── ingress.yaml
│ ├── networkpolicy.yaml
│ ├── hooks/
│ │ └── db-migrate.yaml
│ └── tests/
│ └── test-endpoints.yaml
└── ci/
└── test-values.yaml
Chart.yaml
apiVersion: v2
name: webapp
version: 1.0.0
appVersion: "1.0.0"
description: Application web complète avec frontend, backend et dépendances
dependencies:
- name: postgresql
version: "12.x.x"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: "17.x.x"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
values.yaml
# Global
global:
imageRegistry: ""
# Frontend
frontend:
replicaCount: 2
image:
repository: nginx
tag: "1.25"
service:
type: ClusterIP
port: 80
resources:
limits:
cpu: 200m
memory: 256Mi
# Backend
backend:
replicaCount: 2
image:
repository: hashicorp/http-echo
tag: "0.2.3"
message: "API Response"
service:
type: ClusterIP
port: 5678
resources:
limits:
cpu: 500m
memory: 512Mi
# Ingress
ingress:
enabled: false
className: nginx
hosts:
- host: webapp.local
paths:
- path: /
pathType: Prefix
service: frontend
- path: /api
pathType: Prefix
service: backend
# Dependencies
postgresql:
enabled: true
auth:
database: webapp
username: webapp
redis:
enabled: true
architecture: standalone
Deployment
# Dépendances
helm dependency update ./webapp-chart
# Installation développement
helm install webapp-dev ./webapp-chart \
--namespace dev \
--create-namespace
# Installation production
helm install webapp-prod ./webapp-chart \
--namespace production \
--create-namespace \
-f values-production.yaml \
--atomic \
--wait
# Tests
helm test webapp-dev
3 - Review quiz
-
What is the difference between
helm templateandhelm install --dry-run? -
How do you override a nested value with --set?
-
What is the priority order of values?
-
Which annotation defines a pre-upgrade hook?
-
How do you view the values used in a release?
Answers
-
helm templaterenders the manifests locally without connecting to the cluster.--dry-runcontacts the cluster for validation. -
--set parent.child.key=value -
values.yaml < -f files (in order) < --set/--set-string
-
"helm.sh/hook": pre-upgrade -
helm get values <release-name>or--allto include the defaults
Course summary
Congratulations! You have completed the Helm course. You now have a firm grasp of:
- The installation and configuration of Helm
- The fundamental concepts (Charts, Releases, Repositories)
- The creation of custom charts
- Go templates and Helm functions
- Managing HTTP and OCI repositories
- The release lifecycle
- Hooks and tests
- The best practices
Next steps
- Practice with existing charts
- Create charts for your applications
- Explore Helmfile for multi-release management
- Integrate Helm into your CI/CD pipelines