Skip to content

Module 3 — Helm : packager un déploiement Kubernetes

Bonne lecture et bon apprentissage ! Junior TSAFACK – 12/09/2026 Temps de lecture estimé : 9 minutes


Le Module 2 a appliqué des fichiers YAML statiques avec kubectl apply. Ça fonctionne, mais devient pénible dès qu’il faut faire varier des valeurs selon l’environnement (nombre de répliques, tag d’image, nom de domaine) : soit on maintient plusieurs copies presque identiques des fichiers YAML, soit on les génère avec des scripts maison. Helm est le gestionnaire de paquets de Kubernetes : un chart est un modèle de manifestes paramétrable, une release est une instance de ce chart déployée avec des valeurs précises.

$ helm create demo-chart
Creating demo-chart
$ find demo-chart -type f
demo-chart/values.yaml
demo-chart/Chart.yaml
demo-chart/templates/deployment.yaml
demo-chart/templates/service.yaml
demo-chart/templates/hpa.yaml
demo-chart/templates/ingress.yaml
demo-chart/templates/serviceaccount.yaml
demo-chart/templates/tests/test-connection.yaml

helm create scaffold un chart de démarrage complet et fonctionnel — Deployment, Service, HPA, Ingress, ServiceAccount — qu’on adapte ensuite à son application plutôt que d’écrire chaque fichier depuis zéro.

$ helm lint demo-chart
==> Linting demo-chart
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
$ helm install demo-release demo-chart --namespace demo-app --dry-run
NAME: demo-release
STATUS: pending-install
MANIFEST:
--- (les manifestes générés, affichés mais pas appliqués)

--dry-run rend visible exactement ce que Helm va envoyer à Kubernetes, sans encore l’appliquer — l’équivalent direct de terraform plan (vu dans le module Infrastructure as Code) ou d’un Change Set CloudFormation.

Un vrai bug rencontré en déployant ce chart

Section titled “Un vrai bug rencontré en déployant ce chart”

Après avoir pointé values.yaml vers l’image de l’application (docker-avance-app:latest, celle du Module 1, qui écoute sur le port 5000), le premier helm install a semblé fonctionner — mais les pods ne passaient jamais à l’état prêt :

$ kubectl get pods -n demo-app -l app.kubernetes.io/instance=demo-release
NAME READY STATUS AGE
demo-release-demo-chart-55fc8d97f9-rvp6x 0/1 Running 26s
demo-release-demo-chart-55fc8d97f9-wl5r6 0/1 Running 26s
$ kubectl describe pod demo-release-demo-chart-55fc8d97f9-rvp6x -n demo-app
Warning Unhealthy kubelet Readiness probe failed: Get "http://10.42.0.18:80/": dial tcp 10.42.0.18:80: connect: connection refused
Warning Unhealthy kubelet Liveness probe failed: Get "http://10.42.0.18:80/": dial tcp 10.42.0.18:80: connect: connection refused

Diagnostic : le chart scaffoldé par helm create référence partout {{ .Values.service.port }} — dans deployment.yaml (containerPort), dans service.yaml (port), et dans les probes de values.yaml (livenessProbe.httpGet.port, readinessProbe.httpGet.port). Une seule valeur pilote les trois. Or values.yaml par défaut fixe service.port: 80 (pensé pour une image type nginx), alors que l’application Flask de ce cours écoute sur le port 5000. Résultat : Kubernetes sondait le port 80, où rien n’écoutait — connection refused, en boucle, jusqu’à ce que la sonde de vivacité (livenessProbe) tue le conteneur.

La correction, une seule ligne dans values.yaml :

service:
type: ClusterIP
port: 80
port: 5000

Après correction et un helm upgrade :

$ helm upgrade demo-release demo-chart --namespace demo-app --set replicaCount=3
$ kubectl get pods -n demo-app -l app.kubernetes.io/instance=demo-release
NAME READY STATUS AGE
demo-release-demo-chart-7c69d8f464-5dqm9 1/1 Running 94s
demo-release-demo-chart-7c69d8f464-98xsb 1/1 Running 69s
demo-release-demo-chart-7c69d8f464-hsfnb 1/1 Running 80s
$ kubectl run curltest -n demo-app --rm -i --restart=Never --image=curlimages/curl \
-- curl -s http://demo-release-demo-chart.demo-app.svc.cluster.local:5000/
{"message":"Bonjour depuis le conteneur applicatif","visites":53}

La leçon à en tirer : un chart Helm scaffoldé (ou copié d’un exemple en ligne) porte des valeurs par défaut pensées pour son image de référence, pas pour la vôtre. Avant tout helm install en conditions réelles, il faut identifier chaque endroit où une valeur de values.yaml est référencée (grep -rn "Values.service.port" templates/) plutôt que de supposer qu’un seul champ suffit à adapter le chart à une application différente.

$ helm history demo-release -n demo-app
REVISION STATUS DESCRIPTION
1 superseded Install complete
2 superseded Upgrade complete
3 deployed Upgrade complete

Chaque helm upgrade crée une nouvelle révision — helm rollback demo-release 1 reviendrait instantanément à l’état de la révision 1, sans avoir à se souvenir manuellement de la configuration précédente.

$ helm uninstall demo-release -n demo-app
release "demo-release" uninstalled
$ kubectl get pods -n demo-app -l app.kubernetes.io/instance=demo-release
No resources found in demo-app namespace.

Une seule commande supprime toutes les ressources créées par la release (Deployment, Service, ServiceAccount…) — contrairement à un kubectl delete -f qui nécessite de lister chaque fichier manuellement.

Gestion de configuration avec Ansible