Installer Kubernetes en local n’a plus rien d’un parcours du combattant en 2026, mais la plupart des tutoriels s’arrêtent à minikube start sans jamais montrer comment déployer, exposer et faire tenir en charge une vraie application. Ce guide comble ce vide : on part d’une machine vierge et on termine avec un cluster fonctionnel, une application Node.js conteneurisée, un Ingress qui route le trafic HTTP et un chart Helm prêt pour la production. Chaque commande a été testée sur Kubernetes v1.35, la branche stable utilisée par les tutoriels francophones les plus récents mis à jour cet été 2026.
Que vous prépariez une certification, une migration d’infrastructure ou simplement un environnement de test fiable, ce tutoriel vous évite les pièges classiques : versions de kubectl désynchronisées, add-ons minikube oubliés, manifestes YAML mal indentés ou Ingress qui ne route rien. Comptez environ 90 minutes pour suivre l’ensemble des 12 étapes.
Ce guide ne se limite pas à un simple “hello world” conteneurisé. On y déploie une application avec deux réplicas, un routage HTTP via Ingress, une mise à l’échelle automatique déclenchée par la charge CPU, une supervision Prometheus/Grafana, un contrôle d’accès RBAC et un packaging Helm réutilisable. C’est le socle que la plupart des équipes retrouvent, sous une forme ou une autre, derrière leurs applications en production. Le maîtriser en local, sans risquer de casser un environnement partagé, reste la manière la plus sûre d’apprendre.
Pourquoi apprendre Kubernetes reste incontournable en 2026
Kubernetes domine toujours l’orchestration de conteneurs en Europe. Les recherches françaises autour du mot-clé “kubernetes” dépassent 14 000 requêtes mensuelles avec une concurrence publicitaire jugée faible, un signal net que la demande d’apprentissage progresse plus vite que l’offre de contenus à jour. Les organismes de formation comme SFEIR Institute publient régulièrement de nouveaux parcours pédagogiques, et la documentation officielle en français a été rafraîchie fin juillet 2026, preuve que le projet continue d’investir dans l’accessibilité pour les développeurs non anglophones.
Sur le plan technique, la branche stable de Kubernetes utilisée dans les environnements de développement actuels est la 1.35.x, avec un client kubectl aligné sur la même version majeure pour éviter les incompatibilités d’API. Les outils satellites ont eux aussi avancé : Helm est distribué en version 3.16 et plus, minikube reste l’environnement local de référence pour simuler un cluster complet sans toucher à un vrai fournisseur cloud, et l’add-on Ingress NGINX embarqué permet de tester du routage HTTP réaliste directement sur son poste.
Ce contexte technique compte, car un tutoriel calé sur une version périmée de kubectl reproduit souvent des erreurs de compatibilité que le lecteur met du temps à comprendre : une API dépréciée dans une ancienne version peut simplement disparaître dans la suivante. C’est pourquoi ce guide s’appuie systématiquement sur les commandes officielles pour récupérer la dernière version stable, plutôt que sur un numéro figé dans le texte.
Ce tutoriel s’adresse aux développeurs qui maîtrisent déjà Docker et les bases de la ligne de commande Linux, mais qui n’ont jamais orchestré de conteneurs à grande échelle. On ne suppose aucune connaissance préalable de Kubernetes.
Ce n’est pas un hasard si les organismes de formation français continuent de remplir leurs sessions Kubernetes tout au long de l’année : la compétence reste recherchée par les équipes plateforme, SRE et DevOps, bien au-delà des seules startups. Les offres d’emploi qui mentionnent Docker mentionnent presque systématiquement Kubernetes en compétence associée, ce qui explique pourquoi tant de développeurs cherchent un chemin d’apprentissage pratique plutôt qu’une simple lecture de documentation théorique.
Comprendre les concepts clés avant de se lancer
Avant d’écrire la moindre commande, il vaut mieux fixer le vocabulaire. Un Pod est la plus petite unité déployable dans Kubernetes : il contient un ou plusieurs conteneurs qui partagent le même réseau et le même stockage. On ne crée presque jamais un Pod directement en production, on passe par un objet de plus haut niveau qui le gère pour nous.
Un Deployment est justement cet objet de plus haut niveau. Il décrit combien de réplicas d’un Pod doivent tourner en permanence, et Kubernetes en recrée automatiquement un nouveau si l’un d’eux plante ou si le nœud qui l’héberge tombe. C’est ce mécanisme d’auto-guérison qui distingue Kubernetes d’un simple script de déploiement Docker.
Un Service résout un problème différent : les Pods sont éphémères, leur adresse IP change à chaque recréation. Le Service fournit une adresse stable et répartit le trafic entre les Pods actifs derrière lui, un peu comme un load balancer interne. Dans ce tutoriel, on utilise un Service de type ClusterIP, accessible uniquement depuis l’intérieur du cluster, ce qui explique pourquoi on ajoute ensuite un Ingress pour exposer l’application vers l’extérieur.
Enfin, un Namespace cloisonne les ressources d’un cluster en environnements logiques distincts, par exemple monitoring pour la stack Prometheus à l’étape 9. C’est l’équivalent d’un dossier qui isole les noms de ressources et, combiné à RBAC, les permissions d’accès entre équipes ou projets.
Deux autres objets méritent d’être connus même s’ils ne sont pas utilisés directement dans ce tutoriel : le ConfigMap, qui externalise la configuration non sensible d’une application (URL d’API, niveau de log) hors de l’image Docker, et le Secret, son équivalent pour les données sensibles comme les mots de passe ou les jetons d’API, encodées en base64 par défaut mais idéalement chiffrées au repos via un fournisseur externe comme Sealed Secrets ou un coffre-fort type Vault. Séparer la configuration du code applicatif évite de reconstruire une image entière pour changer une simple variable d’environnement.
Prérequis et versions nécessaires
Avant de commencer, vérifiez que votre environnement remplit ces conditions. Un cluster minikube complet avec les add-ons Ingress et metrics-server actifs consomme des ressources réelles, mieux vaut ne pas travailler sur une machine sous-dimensionnée.
| Composant | Version minimale recommandée | Rôle dans ce tutoriel |
|---|---|---|
| Système d’exploitation | Linux x86_64 (Ubuntu 22.04+ ou équivalent) | Hôte du cluster local |
| Docker Engine | 24.0 ou supérieur | Driver de conteneurs pour minikube et build d’images |
| minikube | Dernière version stable (binaire officiel) | Cluster Kubernetes local à un nœud |
| kubectl | v1.35.x (aligné sur le cluster) | Client en ligne de commande pour piloter le cluster |
| Helm | 3.16 ou supérieur | Gestionnaire de paquets Kubernetes (charts) |
| Node.js | 20 LTS ou supérieur | Application de démonstration |
| RAM disponible | 8 Go minimum alloués au cluster | Exécution stable des pods et add-ons |
| CPU | 4 cœurs alloués minimum | Autoscaling et monitoring sans lenteur |
Si votre machine ne dispose pas de 8 Go de RAM libres, réduisez les valeurs de --memory dans les commandes ci-dessous, mais sachez que Prometheus et Grafana (étape 8) deviendront instables sous 4 Go.
Étape 1 : installer minikube et configurer l’environnement local
On commence par récupérer le binaire minikube depuis le dépôt officiel Google, puis on l’installe dans le PATH système. Cette méthode garantit d’obtenir toujours la dernière version stable sans dépendre d’un gestionnaire de paquets tiers parfois en retard.
# Télécharger et installer minikube (Linux x86_64)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Vérifier l'installation
minikube version
Ensuite on installe kubectl en interrogeant l’API officielle pour connaître la version stable courante, ce qui évite de coder en dur un numéro de version qui deviendra obsolète :
# Récupérer la version stable et installer kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/kubectl
# Vérifier
kubectl version --client
Sortie attendue : Client Version: v1.35.3 (ou une version 1.35.x plus récente selon la date d’installation). Si votre sortie affiche une branche 1.3x très différente, ce n’est pas grave : gardez simplement kubectl et le cluster sur la même version majeure et mineure pour éviter les erreurs de compatibilité d’API.
Un écart d’une version mineure entre le client et le serveur reste toléré par Kubernetes, mais un écart de deux versions ou plus expose à des erreurs d’API dépréciées. Si vous gérez plusieurs clusters avec des versions différentes au quotidien, l’outil kubectx et son compagnon kubens permettent de basculer rapidement de contexte sans retaper de longues commandes --context.
Étape 2 : démarrer le cluster avec les ressources adéquates
On démarre maintenant minikube en fixant explicitement la version de Kubernetes et les ressources allouées. Ne laissez jamais les valeurs par défaut pour un usage sérieux : elles sont souvent trop faibles pour faire tourner Prometheus, Grafana et l’autoscaling en parallèle.
minikube start \
--kubernetes-version=v1.35.3 \
--cpus=4 \
--memory=8192 \
--driver=docker
# Activer les add-ons nécessaires
minikube addons enable ingress
minikube addons enable metrics-server
minikube addons enable dashboard
Vérifiez que le nœud est opérationnel :
kubectl get nodes
# Sortie attendue :
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 45s v1.35.3
Si le statut reste bloqué sur NotReady plus de deux minutes, passez directement à la section dépannage plus bas : c’est le blocage numéro un rencontré par les débutants.
Notez que le choix du driver a un impact réel sur les performances. Le driver Docker, utilisé ici, s’appuie sur un conteneur Docker pour simuler le nœud, ce qui le rend rapide à démarrer et facile à déboguer. Les drivers basés sur une VM complète (VirtualBox, HyperKit) offrent une isolation plus proche d’un vrai environnement de production, mais démarrent plus lentement et consomment davantage de ressources.
Étape 3 : créer une application Node.js de démonstration
Plutôt que de déployer un exemple générique “hello world”, on construit une mini API Express qui expose un endpoint de santé, un endpoint de charge CPU (utile pour tester l’autoscaling à l’étape 7) et un compteur en mémoire.
mkdir demo-app && cd demo-app
npm init -y
npm install express
cat > server.js << 'EOF'
const express = require('express');
const app = express();
let counter = 0;
app.get('/', (req, res) => {
counter++;
res.json({ message: 'Bonjour depuis Kubernetes', counter, host: process.env.HOSTNAME });
});
app.get('/health', (req, res) => res.status(200).send('OK'));
app.get('/charge', (req, res) => {
const fin = Date.now() + 500;
while (Date.now() < fin) { Math.sqrt(Math.random()); }
res.send('Charge CPU terminee');
});
app.listen(3000, () => console.log('Serveur demarre sur le port 3000'));
EOF
Testez-la en local avant de la conteneuriser (node server.js puis curl localhost:3000) : un bug détecté ici coûte trente secondes, le même bug détecté après un déploiement Kubernetes complet coûte facilement dix minutes de debug.
L’endpoint /health n’est pas décoratif : il servira de cible au readinessProbe défini à l’étape 5, le mécanisme par lequel Kubernetes détermine si un Pod est prêt à recevoir du trafic. Sans cet endpoint, il faudrait se rabattre sur une simple vérification de port TCP, moins fiable pour détecter une application qui a démarré son processus mais n’a pas encore fini d’initialiser ses dépendances.
Étape 4 : construire et pousser l’image Docker
On écrit un Dockerfile minimal en plusieurs étapes pour garder une image légère, puis on la construit directement dans le daemon Docker de minikube afin d’éviter de passer par un registre externe pour ce tutoriel.
cat > Dockerfile << 'EOF'
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY server.js .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
EOF
# Pointer le shell vers le daemon Docker interne de minikube
eval $(minikube docker-env)
docker build -t demo-app:1.0 .
docker images | grep demo-app
Le point critique ici : la commande eval $(minikube docker-env) ne fonctionne que dans le terminal courant. Ouvrez un nouveau terminal et l'image ne sera plus visible pour le cluster, un piège classique détaillé plus bas.
L'utilisation d'un build multi-étapes (node:20-alpine comme base finale, sans les outils de compilation) réduit sensiblement la taille de l'image finale par rapport à une image basée sur Debian complète. En production, cette différence de poids se traduit directement par des temps de démarrage de Pod plus courts et une surface d'attaque réduite, puisque moins de paquets système sont présents dans le conteneur final.
Étape 5 : écrire les manifestes Kubernetes (Deployment et Service)
On sépare volontairement le Deployment (qui gère les pods) du Service (qui les expose en interne). C'est la structure standard recommandée par la documentation officielle, plutôt qu'un fichier unique qui mélange les deux responsabilités.
cat > deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo-app
spec:
replicas: 2
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: demo-app:1.0
imagePullPolicy: Never
ports:
- containerPort: 3000
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "250m"
memory: "128Mi"
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: demo-app-service
spec:
selector:
app: demo-app
ports:
- port: 80
targetPort: 3000
type: ClusterIP
EOF
kubectl apply -f deployment.yaml
Le champ imagePullPolicy: Never est indispensable dans ce contexte : sans lui, Kubernetes tente de télécharger l'image depuis Docker Hub, échoue puisque demo-app:1.0 n'existe que localement, et affiche l'erreur ImagePullBackOff.
Étape 6 : vérifier le déploiement et consulter les logs
Avant d'exposer l'application au monde extérieur, on vérifie que les deux réplicas tournent correctement.
kubectl get pods -l app=demo-app
kubectl get deployment demo-app
kubectl logs -l app=demo-app --tail=20
# Sortie attendue :
# NAME READY STATUS RESTARTS AGE
# demo-app-7d8f9c6b5d-abc12 1/1 Running 0 32s
# demo-app-7d8f9c6b5d-xyz89 1/1 Running 0 32s
Un test rapide en local, sans passer par l'Ingress, confirme que le Service route bien le trafic entre les deux pods :
kubectl port-forward svc/demo-app-service 8080:80
# Dans un autre terminal :
curl localhost:8080
Étape 7 : configurer l'Ingress pour un routage HTTP propre
Le port-forward est pratique pour déboguer, mais ce n'est pas une solution d'exposition durable. On configure donc une ressource Ingress qui s'appuie sur l'add-on NGINX activé à l'étape 2.
cat > ingress.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: demo-app.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-app-service
port:
number: 80
EOF
kubectl apply -f ingress.yaml
# Recuperer l'IP du cluster minikube
minikube ip
Ajoutez ensuite une entrée dans /etc/hosts associant l'IP retournée à demo-app.local, puis testez avec curl http://demo-app.local. Sous Linux, la commande minikube tunnel lancée dans un terminal séparé est parfois nécessaire selon le driver utilisé pour que le trafic externe atteigne réellement le contrôleur Ingress.
Étape 8 : mettre en place l'autoscaling horizontal (HPA)
Avec metrics-server déjà actif, on peut brancher un Horizontal Pod Autoscaler qui ajuste automatiquement le nombre de réplicas selon la charge CPU observée.
kubectl autoscale deployment demo-app --cpu-percent=50 --min=2 --max=6
kubectl get hpa demo-app --watch
# Dans un autre terminal, generer de la charge :
for i in $(seq 1 200); do curl -s http://demo-app.local/charge & done
Observez la colonne REPLICAS grimper progressivement de 2 vers 6 lorsque la charge CPU moyenne dépasse 50 %, puis redescendre après quelques minutes d'inactivité. C'est le comportement attendu d'un cluster de production, reproduit ici à petite échelle.
Étape 9 : monitorer le cluster avec Prometheus et Grafana
Plutôt que d'écrire des manifestes Prometheus à la main, on utilise Helm pour installer le chart communautaire kube-prometheus-stack, qui regroupe Prometheus, Grafana et Alertmanager en une seule commande.
# Installer Helm si ce n'est pas deja fait
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
# Ajouter le depot et installer la stack
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
--set grafana.adminPassword=admin123
L'installation prend deux à trois minutes selon votre connexion. Une fois les pods du namespace monitoring passés à Running, exposez Grafana avec kubectl port-forward -n monitoring svc/monitoring-grafana 3001:80 et connectez-vous avec l'identifiant admin et le mot de passe défini ci-dessus.
Le tableau de bord par défaut fourni par le chart affiche déjà l'usage CPU et mémoire par namespace, ce qui suffit pour repérer un pod qui consomme anormalement plus que ses voisins. Sur un cluster de développement, ce niveau de détail est largement suffisant. Sur un cluster de production, on y ajoute généralement des alertes Alertmanager déclenchées sur des seuils métier plutôt que de se contenter d'une surveillance visuelle du dashboard, ce qui permet d'être notifié avant que l'incident ne devienne visible pour les utilisateurs.
Étape 10 : sécuriser le cluster avec RBAC et des Network Policies
Un cluster sans contrôle d'accès ni isolation réseau n'a rien de production-ready. On crée un compte de service dédié avec des droits limités, plutôt que d'utiliser le compte admin par défaut.
cat > rbac.yaml << 'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
name: demo-app-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: demo-app-role
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: demo-app-binding
subjects:
- kind: ServiceAccount
name: demo-app-sa
roleRef:
kind: Role
name: demo-app-role
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f rbac.yaml
Suivez le principe du moindre privilège : n'accordez jamais le verbe delete ou * à un ServiceAccount applicatif sans raison précise. La documentation officielle sur les bonnes pratiques RBAC détaille les schémas d'audit recommandés pour les environnements multi-équipes.
Ce Role reste volontairement limité au namespace courant : c'est la différence entre un Role et un ClusterRole. Le premier ne s'applique qu'à un namespace, le second s'étend à l'ensemble du cluster. Réserver les ClusterRole aux comptes d'administration et cantonner les applications à des Role de namespace réduit fortement l'impact d'un ServiceAccount compromis, puisqu'un attaquant qui obtiendrait son token ne pourrait agir que dans un périmètre restreint.
Étape 11 : empaqueter l'application en chart Helm
Dernière étape technique : transformer les manifestes bruts en chart Helm réutilisable, pour pouvoir déployer la même application sur plusieurs environnements (dev, staging, prod) avec des valeurs différentes.
helm create demo-app-chart
cd demo-app-chart
# Remplacer image.repository et image.tag dans values.yaml
sed -i 's/repository: nginx/repository: demo-app/' values.yaml
sed -i 's/tag: ""/tag: "1.0"/' values.yaml
sed -i 's/pullPolicy: IfNotPresent/pullPolicy: Never/' values.yaml
# Valider le chart avant deploiement
helm lint .
helm install demo-app-release . --dry-run --debug
# Deploiement reel
helm install demo-app-release .
Le --dry-run --debug est une étape que trop de tutoriels sautent : il affiche le YAML final généré par Helm sans rien appliquer au cluster, ce qui permet de repérer une erreur de templating avant qu'elle ne casse un déploiement en production.
Étape 12 : nettoyer l'environnement et gérer le cycle de vie
Un cluster de test qui tourne en permanence consomme de la RAM et de la batterie inutilement. Voici les commandes de nettoyage à connaître selon le niveau de "reset" souhaité.
# Supprimer uniquement les ressources applicatives
helm uninstall demo-app-release
kubectl delete -f ingress.yaml -f deployment.yaml -f rbac.yaml
# Mettre le cluster en pause sans le detruire
minikube pause
# Arreter completement le cluster (conserve l'etat)
minikube stop
# Supprimer entierement le cluster (repart de zero)
minikube delete
Privilégiez minikube stop entre deux sessions de travail : contrairement à minikube delete, il conserve la configuration et les images Docker déjà construites, ce qui vous fait gagner plusieurs minutes au redémarrage.
Automatiser le déploiement avec un pipeline CI/CD
Une fois les douze étapes maîtrisées manuellement, l'étape logique suivante consiste à automatiser le cycle build-push-deploy plutôt que de retaper les commandes à chaque changement de code. Voici un exemple de workflow GitHub Actions qui construit l'image, la pousse vers un registre, puis déclenche le déploiement sur un cluster distant via kubectl.
name: deploy-demo-app
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Connexion au registre
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin ghcr.io
- name: Build et push de l'image
run: |
docker build -t ghcr.io/mon-org/demo-app:${{ github.sha }} .
docker push ghcr.io/mon-org/demo-app:${{ github.sha }}
- name: Configurer kubectl
run: echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig.yaml
- name: Deployer sur le cluster
run: |
export KUBECONFIG=kubeconfig.yaml
kubectl set image deployment/demo-app demo-app=ghcr.io/mon-org/demo-app:${{ github.sha }}
kubectl rollout status deployment/demo-app
Deux points de vigilance sur ce pipeline. D'abord, ne stockez jamais un kubeconfig en clair dans le dépôt : passez toujours par les secrets chiffrés de votre plateforme CI/CD. Ensuite, la commande kubectl rollout status en fin de job est ce qui transforme un simple déploiement "fire and forget" en déploiement vérifié : le job échoue explicitement si les nouveaux Pods ne passent jamais à l'état Ready, plutôt que de rapporter un succès trompeur.
Sur un vrai cluster de production, ce même schéma s'adapte aussi bien à GitLab CI qu'à Jenkins ou Argo CD, ce dernier ajoutant une couche de synchronisation continue entre l'état déclaré dans Git et l'état réel du cluster (l'approche GitOps mentionnée plus loin dans les conseils avancés).
Erreurs fréquentes et comment les éviter
Voici les cinq pièges qui reviennent le plus souvent dans les retours d'expérience de développeurs débutant avec Kubernetes en local. Chacun d'entre eux est silencieux : Kubernetes ne bloque jamais l'application d'un manifeste fautif, il se contente de laisser le Pod échouer, ce qui oblige à développer le réflexe d'inspection systématique plutôt que de supposer qu'une commande qui s'exécute sans erreur a forcément fonctionné.
- Oublier
eval $(minikube docker-env)dans un nouveau terminal. L'image construite reste invisible pour le cluster et le pod afficheImagePullBackOff. Réexécutez la commande à chaque nouvelle session de terminal. - Confondre
imagePullPolicy: AlwaysetNeveren environnement local. AvecAlways, Kubernetes ignore votre image locale et tente de la télécharger depuis un registre distant, provoquant un échec silencieux. - Indentation YAML incohérente. Un espace de trop ou un tabulateur glissé dans un manifeste casse le parsing sans message d'erreur clair. Validez toujours avec
kubectl apply --dry-run=client -f fichier.yamlavant l'application réelle. - Ressources CPU/mémoire non définies. Sans
requestsnilimits, un pod peut monopoliser tout le nœud et déclencher des évictions en cascade sur les autres pods. - Oublier le
readinessProbe. Sans lui, Kubernetes route du trafic vers un pod qui n'a pas encore terminé son démarrage, provoquant des erreurs 502 intermittentes lors des déploiements.
Un sixième piège, plus subtil, touche les développeurs venant du monde Docker Compose : l'absence de PersistentVolumeClaim pour les données qui doivent survivre à un redémarrage de Pod. Contrairement à un conteneur Docker classique, un Pod Kubernetes est considéré comme jetable par conception, toute donnée écrite sur son système de fichiers local disparaît à la prochaine recréation.
Un septième piège concerne les limites de ressources trop généreuses par excès de prudence. Fixer des limits très hautes "pour être tranquille" revient à priver Kubernetes de sa capacité à planifier efficacement les Pods sur les nœuds disponibles, puisque le scheduler réserve l'espace annoncé même s'il n'est jamais consommé. Mieux vaut partir de valeurs mesurées, comme celles utilisées à l'étape 5, et les ajuster ensuite avec les métriques réelles collectées par Prometheus.
Dépannage : les problèmes les plus courants
Cette section couvre les incidents les plus fréquemment rencontrés au fil de ce tutoriel, avec leur diagnostic et leur correction. Trois commandes reviennent systématiquement dans le diagnostic : kubectl describe pod pour lire les événements récents attachés à une ressource, kubectl logs pour consulter la sortie du conteneur, et kubectl get events --sort-by=.lastTimestamp pour voir l'historique complet du cluster dans l'ordre chronologique. Prenez le réflexe de les lancer avant de chercher une solution en ligne.
| Symptôme | Cause probable | Solution |
|---|---|---|
Le nœud reste en NotReady | Ressources insuffisantes allouées au driver Docker | Augmentez --memory et --cpus au démarrage de minikube, puis relancez |
ImagePullBackOff sur le pod | Image construite hors du daemon Docker de minikube | Réexécutez eval $(minikube docker-env) puis reconstruisez l'image |
| Ingress renvoie 404 | Add-on ingress non activé ou ingressClassName manquant | Vérifiez minikube addons list et ajoutez ingressClassName: nginx |
curl demo-app.local échoue | Entrée manquante dans /etc/hosts ou tunnel non lancé | Ajoutez l'IP de minikube ip dans /etc/hosts et lancez minikube tunnel |
HPA affiche <unknown> pour les métriques | metrics-server pas encore prêt ou désactivé | Patientez 60 secondes après minikube addons enable metrics-server puis relancez la commande |
Pods Prometheus restent en Pending | Mémoire insuffisante sur le nœud | Relancez minikube avec au moins 8 Go de RAM allouée |
helm install échoue avec une erreur de templating | Valeur manquante ou mal typée dans values.yaml | Lancez helm lint . puis helm install --dry-run --debug pour isoler la ligne fautive |
Les pods redémarrent en boucle (CrashLoopBackOff) | Erreur applicative au démarrage ou probe mal configurée | Inspectez avec kubectl logs et kubectl describe pod pour voir l'erreur exacte |
Conseils avancés pour la production
Une fois ce tutoriel maîtrisé sur minikube, plusieurs ajustements sont nécessaires avant tout déploiement en environnement réel.
D'abord, remplacez le driver local par un vrai fournisseur cloud (EKS, GKE, AKS) ou un cluster managé, car minikube n'est jamais recommandé en production : il ne gère qu'un seul nœud et ne réplique pas la haute disponibilité d'un vrai control plane. Ensuite, ajoutez des Network Policies pour restreindre les communications pod à pod par défaut, plutôt que de laisser un trafic est-ouest totalement ouvert. Combinez cette isolation réseau avec une politique de sécurité des pods (Pod Security Standards) en mode restricted pour bloquer les conteneurs qui tentent de s'exécuter en root.
Sur le plan des déploiements, adoptez une stratégie GitOps avec Argo CD ou Flux plutôt que des kubectl apply manuels : chaque changement d'infrastructure devient alors traçable et réversible via Git. Enfin, configurez des sondes de liveness en plus des sondes de readiness déjà vues à l'étape 5, et fixez systématiquement un PodDisruptionBudget pour éviter qu'une mise à jour de nœud ne fasse tomber toutes les réplicas d'un service simultanément.
Côté observabilité, ne vous arrêtez pas à Prometheus et Grafana pour les métriques : ajoutez une solution de traçage distribué comme OpenTelemetry dès que votre architecture dépasse trois ou quatre microservices, car un simple graphique CPU ne dira jamais pourquoi une requête met deux secondes de plus à traverser la chaîne d'appels. Sur le plan des coûts, gardez à l'esprit que des requests mal dimensionnées sont la première source de gaspillage sur un cluster managé facturé à la ressource réservée, bien avant le coût des nœuds eux-mêmes : un outil comme le VerticalPodAutoscaler en mode recommandation aide à ajuster ces valeurs sur la base de l'usage réel observé.
Kubernetes local vs cluster managé : quand basculer
Une question revient souvent une fois ce tutoriel terminé : faut-il rester sur minikube ou migrer vers un service managé ? Le tableau ci-dessous résume les cas d'usage typiques.
En pratique, la bascule se fait rarement d'un coup. La plupart des équipes gardent minikube (ou son équivalent kind) pour le développement quotidien et les tests d'intégration en CI, tout en réservant le cluster managé aux environnements de staging et de production. Cette séparation limite les coûts d'infrastructure pendant les phases de développement, où le trafic réel est nul, tout en garantissant que le comportement observé en local reste transposable puisque les manifestes YAML restent identiques d'un environnement à l'autre.
| Critère | minikube (local) | Cluster managé (EKS/GKE/AKS) |
|---|---|---|
| Coût | Gratuit, limité à votre machine | Facturation à l'usage (control plane + nœuds) |
| Haute disponibilité | Non, un seul nœud | Oui, control plane répliqué sur plusieurs zones |
| Cas d'usage recommandé | Apprentissage, tests locaux, développement | Production, staging partagé, charge réelle |
| Mise à l'échelle | Limitée aux ressources de la machine hôte | Autoscaling de nœuds natif |
| Complexité de mise en place | Faible, une commande suffit | Moyenne à élevée, nécessite une configuration IAM/réseau |
Projet complet : récapitulatif de l'architecture finale
À l'issue des 12 étapes, votre cluster local héberge une architecture complète : un Deployment à deux réplicas de l'application Node.js, un Service ClusterIP qui les expose en interne, un Ingress NGINX qui route le trafic HTTP externe, un HPA qui ajuste automatiquement le nombre de pods selon la charge CPU, une stack Prometheus/Grafana qui collecte et visualise les métriques, un ServiceAccount avec des droits RBAC limités, et un chart Helm qui empaquette le tout pour un redéploiement reproductible sur n'importe quel environnement.
C'est exactement le squelette qu'on retrouve derrière la plupart des applications conteneurisées en production, à l'échelle d'un cluster multi-nœuds près. Reproduire cette architecture en local est le meilleur moyen de comprendre chaque brique avant de l'opérer à grande échelle.
Gardez ce projet comme base de travail pour vos prochains apprentissages : ajoutez une base de données via un StatefulSet, expérimentez un second microservice qui communique avec l'API existante via le Service interne, ou remplacez le driver Docker par un vrai cluster managé pour observer les différences de comportement décrites dans le tableau comparatif ci-dessus. Chaque itération renforce la compréhension acquise pendant ce tutoriel, bien plus efficacement qu'une nouvelle lecture de la documentation.
Questions fréquentes
Minikube fonctionne-t-il sur Windows et macOS ?
Oui, minikube supporte Windows, macOS et Linux avec plusieurs drivers possibles (Docker, HyperKit, Hyper-V, VirtualBox). Les commandes de ce tutoriel restent identiques, seule l'installation initiale du binaire change.
Peut-on utiliser kind ou k3s à la place de minikube ?
Oui, ce sont des alternatives valables pour un cluster Kubernetes local. Kind s'appuie sur des conteneurs Docker comme nœuds et convient bien aux pipelines CI, tandis que k3s vise les environnements à ressources réduites comme les Raspberry Pi.
Faut-il apprendre Docker avant Kubernetes ?
Oui, fortement recommandé. Kubernetes orchestre des conteneurs, il ne les construit pas. Sans notions de Dockerfile et d'images, les étapes 3 et 4 de ce tutoriel seront difficiles à suivre.
Combien de temps faut-il pour maîtriser Kubernetes ?
Ce tutoriel couvre les fondamentaux opérationnels en 90 minutes, mais la maîtrise complète (réseau avancé, opérateurs personnalisés, multi-cluster) prend généralement plusieurs mois de pratique régulière.
Le chart Helm généré à l'étape 11 est-il utilisable tel quel en production ?
Non sans modification. Le chart par défaut généré par helm create est un point de départ générique : il faut ajuster les probes, les limites de ressources et retirer le imagePullPolicy: Never qui n'a de sens qu'en environnement local.
Pourquoi mon HPA n'affiche aucune métrique CPU ?
Le plus souvent parce que metrics-server vient d'être activé et n'a pas encore terminé sa première collecte. Patientez une minute, ou vérifiez que le pod metrics-server est bien à l'état Running avec kubectl get pods -n kube-system.
Comment mettre à jour une application déjà déployée sans interruption ?
Modifiez le tag d'image dans deployment.yaml, puis appliquez avec kubectl apply -f deployment.yaml ou helm upgrade. Kubernetes exécute par défaut une stratégie de mise à jour progressive (rolling update) qui remplace les pods un par un sans coupure de service, à condition que le readinessProbe soit correctement configuré.
Quelle est la différence entre un Deployment et un StatefulSet ?
Un Deployment convient aux applications sans état (stateless), comme l'API de ce tutoriel. Un StatefulSet est nécessaire pour des applications qui ont besoin d'une identité réseau stable et d'un stockage persistant, comme une base de données.
Kubernetes est-il adapté à un petit projet personnel ?
Pas toujours. Pour une application unique à faible trafic, un simple conteneur Docker sur une VM ou une plateforme comme Cloud Run suffit largement et évite la complexité opérationnelle de Kubernetes. Ce dernier devient pertinent dès que plusieurs services doivent communiquer entre eux, que la charge varie fortement, ou que la haute disponibilité devient une exigence réelle.
Que faire si minikube start échoue avec une erreur de driver ?
Vérifiez d'abord que Docker Engine est bien démarré avec docker ps. Si l'erreur persiste, essayez un autre driver avec minikube start --driver=virtualbox ou consultez minikube logs pour identifier la cause exacte, souvent liée à des extensions de virtualisation désactivées dans le BIOS.
Sources et documentation officielle
Pour approfondir chaque étape, consultez la documentation officielle minikube, le guide de démarrage minikube.sigs.k8s.io, les instructions d'installation de kubectl, la page des releases Kubernetes, le guide d'installation de Helm et les bonnes pratiques RBAC officielles.




