Partie 5 : Migration Helm et résolution finale
Novembre 2025
Pourquoi Helm ?
Après avoir fait tourner le site sur K3s avec des manifests YAML bruts, je voulais :
- Versioning des déploiements
- Rollback facile en cas de problème
- Configuration paramétrable (dev/staging/prod)
- Packaging réutilisable
Helm est le package manager de Kubernetes, comme apt pour Debian ou npm pour Node.js.
Création du Chart Helm
Structure du chart
helm-charts/homefonta/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ └── _helpers.tpl
Chart.yaml
apiVersion: v2
name: homefonta
description: Home-Fonta.fr Flask application
type: application
version: 0.1.0
appVersion: "3.1"
values.yaml (configuration)
replicaCount: 3
image:
repository: nocoblas/home-fonta-web
pullPolicy: Always
tag: "v3.1"
fullnameOverride: "home-fonta-web"
service:
type: ClusterIP
port: 80
targetPort: 80 # NGINX écoute sur 80
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod-dns"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
hosts:
- host: home-fonta.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: wildcard-homefonta-tls
hosts:
- home-fonta.fr
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
livenessProbe:
enabled: true
httpGet:
path: /
port: 80 # Port NGINX, pas Gunicorn !
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
enabled: true
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
# Fix temporaire pour le problème CNI
nodeSelector:
kubernetes.io/hostname: rpi4-master
Premier déploiement avec Helm
# Installation
helm install home-fonta . -n home-fonta --create-namespace
# Vérification
helm list -n home-fonta
NAME NAMESPACE STATUS CHART VERSION
home-fonta home-fonta deployed homefonta-0.1.0 3.1
# Les pods
kubectl get pods -n home-fonta
NAME READY STATUS
home-fonta-web-59c5486fb5-8x9kl 1/1 Running
home-fonta-web-59c5486fb5-nl22t 1/1 Running
home-fonta-web-59c5486fb5-v7x4s 1/1 Running
Le cauchemar : Retour de la lenteur !
Après la migration Helm, catastrophe : le site est redevenu lent !
curl -I https://home-fonta.fr
# 15 secondes d'attente...
curl https://home-fonta.fr/static/style.css
# 504 Gateway Timeout
Investigation
# Logs de l'ingress
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller
upstream timed out (110: Operation timed out) while connecting to upstream
Cause trouvée : Templates mal générés
Le template Helm avait mal généré les configurations :
# CE QUI ÉTAIT GÉNÉRÉ (incorrect)
spec:
containers:
- name: web
ports:
- containerPort: 8000 # Port Gunicorn interne
# CE QU'IL FALLAIT
spec:
containers:
- name: web
ports:
- containerPort: 80 # Port NGINX exposé
Debugging approfondi
1. Vérification du service
kubectl get service home-fonta-web -n home-fonta -o yaml
# Le problème
spec:
ports:
- port: 80
targetPort: 8000 # Pointait vers Gunicorn !
# Correction dans values.yaml
service:
port: 80
targetPort: 80 # Pointer vers NGINX
2. Test avec port-forward
# Test direct du pod
kubectl port-forward -n home-fonta pod/home-fonta-web-xxx 8080:80
curl http://localhost:8080
# Fonctionne !
# Donc le problème est entre le service et le pod
3. Correction des templates Jinja2
Autre problème découvert : Les templates avaient une syntaxe cassée !
<!-- CASSÉ (double fermeture) -->
<img src="{{ url_for('static', filename='images/aigle.jpg') }}') }}">
<!-- CORRIGÉ -->
<img src="{{ url_for('static', filename='images/aigle.jpg') }}">
Script de correction :
#!/bin/bash
# fix_templates.sh
for file in templates/*.html; do
sed -i "s/') }}\"/\"/g" "$file"
done
Solution finale : Refonte complète
Nouveau Dockerfile production
# Multi-stage build pour optimisation
FROM python:3.12-slim AS python-builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
COPY templates/ templates/
# Stage production
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
nginx supervisor \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copier depuis builder
COPY --from=python-builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=python-builder /app /app
# Copier les statiques
COPY static/ /app/static/
# Config NGINX
COPY nginx/default.conf /etc/nginx/sites-enabled/default
# Config Supervisor
RUN echo '[supervisord]' > /etc/supervisor/conf.d/app.conf && \
echo 'nodaemon=true' >> /etc/supervisor/conf.d/app.conf && \
echo '[program:nginx]' >> /etc/supervisor/conf.d/app.conf && \
echo 'command=/usr/sbin/nginx -g "daemon off;"' >> /etc/supervisor/conf.d/app.conf && \
echo '[program:gunicorn]' >> /etc/supervisor/conf.d/app.conf && \
echo 'command=gunicorn --bind 127.0.0.1:8000 --workers 2 app:app' >> /etc/supervisor/conf.d/app.conf
EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
Mise à jour Helm
# Rebuild et push de l'image
docker build -t nocoblas/home-fonta-web:v3.1 .
docker push nocoblas/home-fonta-web:v3.1
# Mise à jour Helm
helm upgrade home-fonta . -n home-fonta
# Rollout restart pour forcer
kubectl rollout restart deployment home-fonta-web -n home-fonta
Résultat final : VICTOIRE !
# Test de performance
for i in {1..10}; do
time curl -s https://home-fonta.fr > /dev/null
done
# Moyenne : 0.152s ! (était 15s)
Métriques finales
| Métrique | Début | Docker | K3s (Flask) | K3s (NGINX) | Amélioration |
|---|---|---|---|---|---|
| Temps de réponse | N/A | 2s | 15s | 15ms | 100x |
| Replicas | 0 | 1 | 3 | 3 | HA |
| SSL | ❌ | ❌ | ✅ | ✅ | Auto |
| Rollback | ❌ | Manuel | Manuel | Helm | 1 cmd |
| Monitoring | ❌ | Docker | kubectl | kubectl + Helm | Pro |
Leçons finales apprises
- Les templates Helm peuvent casser : Toujours vérifier le YAML généré
- targetPort est critique : Doit pointer vers le bon port du container
- Multi-stage builds : Réduisent la taille de l'image
- Supervisor : Pratique pour gérer plusieurs processus
- Port-forward : Outil de debug indispensable
- NGINX + Flask : Architecture qui fonctionne vraiment
Bilan global du projet
Ce qui a été accompli
Migration complète : Site statique → Python → Docker → Flask → K3s → Helm
Performance x100 : De 15s à 150ms
Haute disponibilité : 3 replicas sur cluster
SSL automatique : Let's Encrypt + cert-manager
Infrastructure as Code : Ansible + Helm
CI/CD ready : Push to deploy
Compétences acquises
- Docker : Build, multi-stage, compose
- Kubernetes : Pods, Services, Ingress, PV/PVC
- Helm : Charts, values, templates
- Networking : Reverse proxy, load balancing, SSL
- Troubleshooting : Logs, port-forward, debugging CNI
- Linux : systemd, iptables, cgroups
- Automation : Ansible, scripts bash
- Architecture : Microservices, separation of concerns
Et maintenant ?
Le site tourne parfaitement, mais les redirections vers mes service (passbolt, mon nas, mon stack-arr etc. Ne fonctionnaient plus.
A force de tester pleins de possibilité pour régler le problème en plus de toutes les modifications faites pour trouver le problème de latence j'ai fini par casser tout le system, plus aucun site ne fonctonnait.
Après une semaine de recherche pour récupérer tout ça et une semaine de pause j'ai fini par me faire à l'idée que j'allais tout recommencer afin de revenir sur quelque chose de propre.
Aller hop ! j'ai récupéré les cartes sd des raspberry, j'ai réinstallé l'os et j'ai tout repris à zero, enfin presque !
Il ne faut pas oublier les palaybooks ansible que j'avais créé, ça m'a fait gagner un temps fou pour revenir sur une install k3s toute propre et pouvoir reprendre helm sans le poluer grace à mon passif de bugs, enfin j'ai pu récupérer une infra propre et fonctionnelle.
cette fois-ci c'est bon, le projet continue :
Phase 2 : GitOps avec ArgoCD
- Git comme source de vérité
- Déploiements automatiques
- Rollback par git revert
Phase 3 : CI/CD avec GitHub Actions
- Build automatique
- Tests
- Déploiement sur push
Phase 4 : Migration de la stack média
- Sonarr, Radarr, qBittorrent
- Plex, Overseerr
- NFS sur le NAS pour le stockage
Phase 5 : Monitoring complet
- Prometheus + Grafana
- Loki pour les logs
- Alertmanager
Réflexion finale
Ce qui devait être une simple migration de 4 pages HTML est devenu une transformation complète de mon infrastructure. De fichiers statiques à un cluster Kubernetes production-ready.
Était-ce overkill ? Peut-être.
Ai-je appris énormément ? Absolument !
Le referais-je ? Sans hésiter !
Le HomeLab est le terrain de jeu parfait pour apprendre les technologies modernes. Les erreurs ne coûtent rien (sauf du temps), et les compétences acquises sont directement applicables en entreprise.
Mon conseil : Commencez petit, mais visez grand. Chaque étape est un apprentissage.
Le voyage continue... Rendez-vous pour la Phase 2 !
Ressources
- Repository GitHub : [À venir]
- Site en production : https://home-fonta.fr
- Documentation K3s : https://docs.k3s.io/
- Helm : https://helm.sh/
Merci d'avoir suivi cette aventure technique !