WSL2 + Kubernetes : la configuration qui ne fait pas fondre votre portable

Cet article vous a aidé ?

Vous avez installé Kubernetes en local parce que vous vouliez de la rapidité : itérer vite, tester des charts, déboguer des controllers, peut‑être exécuter une petite pile plateforme.
Puis vos ventilateurs se mettent à hurler, votre SSD commence à trimer, et votre « cluster de dev rapide » devient la raison pour laquelle Slack vous demande si vous êtes en ligne.

WSL2 peut être un excellent endroit pour exécuter Kubernetes — si vous le traitez comme une vraie VM avec contraintes de stockage et de mémoire, et non comme un dossier Linux magique.
Voici la configuration pratique qui évite les modes de défaillance classiques : RAM en fuite, E/S lentes, bizarreries DNS et « pourquoi kubectl bloque ? ».

Ce que vous construisez réellement (et pourquoi ça fait fondre les portables)

Sur Windows avec WSL2, « exécuter Kubernetes » n’est rarement juste « exécuter Kubernetes ».
C’est une pile d’abstractions imbriquées qui ont chacune des opinions sur l’ordonnancement CPU, la récupération de mémoire, la sémantique du système de fichiers et le réseau.
Quand une couche devine mal, votre portable en fait les frais.

La configuration typique Kubernetes sur WSL2 ressemble à ceci :

  • Système hôte Windows
  • VM WSL2 (une VM légère Hyper‑V avec un disque virtuel)
  • Distribution Linux userland (Ubuntu, Debian, etc.)
  • Runtime de conteneurs (Docker Engine, containerd ou la stack nerdctl)
  • Distribution Kubernetes (kind, k3d, minikube, microk8s ou le cluster intégré de Docker Desktop)
  • Vos workloads : bases de données, operators, pipelines de build, contrôleurs d’ingress, maillage de services — aka « petit production »

La fonte se produit généralement à partir d’un de ces trois endroits :

  1. Mémoire : WSL2 met volontiers en cache la page cache et ne la rend pas toujours rapidement. Kubernetes programme les pods jusqu’à ce que le nœud soit « bon »… jusqu’à ce qu’il ne le soit plus.
  2. Stockage : franchir la frontière Windows/Linux peut transformer des E/S normales en incident au ralenti. Les bases de données amplifient ça avec fsync et de petites écritures aléatoires.
  3. Réseau/DNS : kube‑dns, le DNS Windows, les NIC virtuels WSL2 et les clients VPN forment un triangle de tristesse.

L’objectif n’est pas « le rendre rapide pour des benchmarks ». L’objectif est « le rendre suffisamment rapidement et de manière prévisible »,
et, plus important, rendre les modes de défaillance évidents.
La fiabilité en dev compte parce que c’est là que vous décidez ce que vous regretterez en prod.

Quelques faits et contexte historique (pour que les parties bizarres fassent sens)

Ces points sont volontairement courts. Ce sont des mises à jour de modèle mental qui évitent des heures de chasse aux fantômes.

  1. WSL1 faisait de la traduction d’appels système ; WSL2 est un vrai noyau Linux dans une VM. C’est pourquoi WSL2 peut faire tourner Kubernetes correctement, mais aussi pourquoi il se comporte comme une VM avec son propre disque et ses politiques mémoire.
  2. WSL2 stocke les fichiers Linux dans un disque virtuel (VHDX) par défaut. Ce disque peut croître rapidement et ne rétrécit pas toujours sauf si vous le compactez explicitement.
  3. Accéder aux fichiers Linux depuis Windows n’est pas la même chose qu’accéder aux fichiers Windows depuis Linux. Les caractéristiques de performance diffèrent drastiquement, et le chemin lent punira les bases de données et les builds d’images.
  4. Kubernetes n’a pas été conçu pour les portables. Il a été conçu pour des clusters où « un nœud est une VM » et on peut brûler du CPU sur des boucles de reconciliation sans entendre de ventilateurs.
  5. kind exécute Kubernetes dans des conteneurs Docker. C’est excellent pour la reproductibilité, mais cela ajoute une couche supplémentaire où le stockage et le réseau peuvent devenir « créatifs ».
  6. k3s (et donc k3d) a été conçu pour être léger. Il utilise SQLite par défaut, ce qui est acceptable en local, mais il sollicite toujours le stockage si vous cumulez beaucoup de controllers.
  7. cgroups v2 a changé le comportement de l’isolation des ressources. Beaucoup de « pourquoi ma limite mémoire est ignorée ? » sont en réalité des conversations « quel mode de cgroup suis‑je ? ».
  8. Le DNS est un mode de défaillance majeur dans les clusters locaux. Pas parce que le DNS est difficile, mais parce que les VPN d’entreprise et le DNS à horizon partagé peuvent tout remplacer silencieusement.
  9. Les builds d’images punissent les métadonnées du système de fichiers. La différence entre un système de fichiers rapide et un système ponté devient évidente quand vous lancez des builds multi‑étapes avec des milliers de petits fichiers.

Choisir votre Kubernetes local : kind vs k3d vs minikube (et ce que je recommande)

Ma recommandation par défaut : kind dans WSL2, avec contraintes

Pour la plupart des développeurs et SRE travaillant sur la plateforme, kind vous apporte répétabilité, rapidité et teardown propre.
Le cluster est « juste des conteneurs », et vous pouvez corriger la version de Kubernetes facilement.
L’important est de contraindre les ressources WSL2 et de garder vos workloads sur le système de fichiers Linux.

Quand préférer k3d (k3s dans Docker)

Si votre objectif est « exécuter une pile plateforme pratique avec un minimum de surcharge », k3d est excellent.
k3s enlève du superflu : moins de composants, moins de mémoire. Il est indulgent sur des portables modestes.
Il se rapproche aussi de ce que beaucoup d’edge setups utilisent, utile si vous déployez vers des environnements contraints.

Quand utiliser minikube

minikube est pratique quand vous voulez « un outil qui gère plusieurs drivers ».
Mais sur WSL2, minikube peut vous laisser face à une matrice de drivers déroutante : driver Docker, KVM (rarement), Hyper‑V (côté Windows),
et vous passez alors plus de temps à déboguer le driver qu’à déboguer le cluster.
Si vous êtes déjà content avec Docker dans WSL2, le driver Docker de minikube fonctionne.

À éviter (sauf si vous avez une raison)

  • Exécuter des workloads denses en état sur /mnt/c puis accuser Kubernetes de lenteur. Ce n’est pas Kubernetes ; c’est la frontière du système de fichiers qui vous demande d’arrêter.
  • Sur‑allouer CPU et RAM « parce que c’est local ». WSL2 prendra, Windows ripostera, et votre navigateur souffrira.
  • Faire du « prod‑like » avec tout activé. Service mesh + tracing distribué + trois operators + une base + un système CI n’est pas un cluster de dev ; c’est un centre de données hobby.

Une petite blague courte, comme promis : Kubernetes, c’est comme une cuisine avec 30 chefs — personne ne cuisine plus vite, mais tout le monde fait un rapport d’état.

Base WSL2 : limites, noyau et ce que Windows ne vous dira pas

Fixez des limites WSL2 ou acceptez le chaos

Par défaut, WSL2 augmentera l’utilisation mémoire jusqu’à une large fraction de la RAM système.
Ce n’est pas malveillant. C’est Linux qui fait des choses Linux — utiliser la mémoire pour le cache.
Le problème est que Windows ne la récupère pas toujours de manière « polie ».

Placez un fichier .wslconfig dans votre répertoire de profil utilisateur Windows (côté Windows).
Vous voulez un plafond pour la mémoire et le CPU, et vous voulez un swap mais pas un substitut permanent de la RAM.

cr0x@server:~$ cat /mnt/c/Users/$WINUSER/.wslconfig
[wsl2]
memory=8GB
processors=4
swap=4GB
localhostForwarding=true

Décision : Si vous avez 16Go de RAM total, 8Go pour WSL2 est généralement raisonnable.
Si vous avez 32Go, 12–16Go est acceptable. Plus que cela tend à masquer des fuites et des limites de pods mal définies.

Comportement de récupération WSL2 : utilisez les outils que vous avez

La récupération mémoire de WSL2 s’est améliorée, mais elle peut encore sembler collante après des builds lourds ou du churn de cluster.
Si vous devez récupérer de la mémoire rapidement, arrêter WSL est l’outil brutal qui fonctionne.

cr0x@server:~$ wsl.exe --shutdown
...output...

Signification de la sortie : Aucune sortie est normale. Cela arrête toutes les distributions WSL et la VM WSL2.
Décision : Utilisez‑le quand Windows est à court de RAM et que vous avez besoin de récupérer maintenant, pas quand vous debuggez un problème dans le cluster.

Utilisez systemd dans WSL2 (si disponible) et soyez explicite

WSL moderne supporte systemd. Ça rend l’exécution de Docker/containerd et des outils Kubernetes moins maladroite.
Vérifiez si systemd est activé.

cr0x@server:~$ ps -p 1 -o comm=
systemd

Signification de la sortie : Si PID 1 est systemd, vous pouvez utiliser la gestion de services normale.
Si c’est autre chose (comme init), vous devrez gérer les daemons différemment.
Décision : Préférez un WSL avec systemd activé pour la stabilité et moins de mystères « pourquoi ça n’a pas démarré ? ».

Stockage sur WSL2 : la différence entre « ça marche » et « ça ne vous déteste pas »

Règle n°1 : conservez les données Kubernetes sur le système de fichiers Linux

Placez l’état du cluster, les images de conteneurs et les données de volumes persistants sous votre système de fichiers de distribution Linux (par ex. /home, /var).
Évitez de stocker des workloads à forte écriture sur /mnt/c.
La couche d’interop peut convenir pour éditer du code, mais c’est un piège pour les bases de données et tout ce qui dépend fortement de fsync.

Règle n°2 : comprenez où vont vos octets

Docker/containerd stocke les images et les couches modifiables quelque part sous /var/lib.
kind et k3d ajoutent leurs propres couches.
Si vous construisez beaucoup d’images ou exécutez des workloads type CI, votre VHDX grossit. Il peut ne pas se réduire.
Ce n’est pas une faute morale ; c’est le fonctionnement des disques virtuels.

Règle n°3 : mesurez les E/S de la manière simple

Vous n’avez pas besoin d’outils de stockage sophistiqués pour attraper les gros problèmes. Vous avez besoin de deux comparaisons :
performance du FS Linux et performance du FS monté depuis Windows.
Si l’un est 10× plus lent, ne « tunez pas Kubernetes ». Déplacez le workload.

cr0x@server:~$ dd if=/dev/zero of=/home/cr0x/io-test.bin bs=1M count=512 conv=fdatasync
512+0 records in
512+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 1.24 s, 433 MB/s

Signification de la sortie : C’est un test d’écriture séquentielle avec flush. Des centaines de Mo/s sont attendus sur un stockage SSD.
Décision : Si c’est en chiffres simples de Mo/s, votre VM subit une pression E/S ou votre disque est mal en point. Corrigez ça avant Kubernetes.

cr0x@server:~$ dd if=/dev/zero of=/mnt/c/Users/$WINUSER/io-test.bin bs=1M count=256 conv=fdatasync
256+0 records in
256+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 12.8 s, 21.0 MB/s

Signification de la sortie : Si vous voyez cette chute, c’est la voie d’interop.
Décision : Ne placez pas /var/lib/docker, /var/lib/containerd ou les répertoires PV sur /mnt/c.
Gardez le code là si nécessaire, mais conservez les caches de build et les bases de données dans l’espace Linux.

Croissance du VHDX : compacter est une tâche de maintenance, pas un remède unique

Si votre disque virtuel WSL2 grossit à cause des builds d’images et du churn, vous pouvez le compacter — mais le compactage n’est pas automatique.
D’abord, nettoyez à l’intérieur de Linux : supprimez les images inutilisées, prunez les volumes, videz les caches.
Puis compressez depuis Windows. Les étapes exactes diffèrent selon la build Windows et les outils, mais le principe est cohérent :
supprimez les blocs inutilisés dans le guest, puis dites à l’hôte de compacter.

La vérité ennuyeuse : les clusters locaux créent des données. Ils ne suppriment pas les données aussi agressivement que vous le pensez.
Si vous traitez votre environnement dev comme la prod, vous planifierez une maintenance comme en prod. C’est le deal.

Réseau : NodePorts, ingress, DNS et le piège du localhost

Localhost n’est pas une philosophie ; c’est une décision de routage

Dans WSL2, « localhost » peut signifier le localhost Windows ou le localhost WSL selon la manière dont vous avez démarré le processus.
Avec localhostForwarding=true, WSL peut forwarder des ports vers Windows, mais ce n’est pas magique pour tous les modèles de trafic.

Si vous exécutez kind dans WSL2 et exposez un service avec NodePort, vous y accéderez souvent depuis Windows via des ports forwardés
ou en ciblant l’IP de la VM WSL. Les deux fonctionnent. L’important est d’être consistant et de documenter la méthode utilisée par votre équipe.

DNS : le tueur silencieux de kubectl

Beaucoup de plaintes « Kubernetes est lent » sont en réalité des timeouts DNS.
kubectl semble bloqué, mais il attend des appels au serveur API qui ne se résolvent pas proprement.
Les clients VPN aggravent cela en injectant des resolvers ou en forçant du split DNS.

Votre travail est de séparer « serveur API lent » de « résolution de noms lente » en moins de cinq minutes.
Plus tard, vous pourrez discuter avec l’outillage VPN de l’entreprise.

Tâches pratiques (commandes, sorties et décisions)

Ce sont de vraies tâches que vous exécuterez lors de la mise en place et du débogage.
Chacune inclut ce que signifie la sortie et la décision que vous en tirez.
Faites‑les dans l’ordre quand vous construisez un nouveau setup ; faites‑les sélectivement quand tout brûle.

Task 1: Confirmer que vous êtes sur WSL2 (pas WSL1)

cr0x@server:~$ wsl.exe -l -v
  NAME            STATE           VERSION
* Ubuntu-22.04    Running         2

Signification de la sortie : VERSION 2 signifie une vraie VM noyau Linux. VERSION 1 signifie traduction d’appels système.
Décision : Si vous êtes en VERSION 1, stoppez et convertissez. Kubernetes a besoin du vrai comportement du noyau.

Task 2: Vérifier le noyau et le mode cgroup

cr0x@server:~$ uname -r
5.15.146.1-microsoft-standard-WSL2
cr0x@server:~$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

Signification de la sortie : cgroup2 monté signifie hiérarchie unifiée.
Décision : Si vos outils supposent cgroup v1 (anciens configs Docker, certains agents de monitoring), attendez‑vous à des surprises.

Task 3: Vérifier systemd et le contrôle des services

cr0x@server:~$ systemctl is-system-running
running

Signification de la sortie : systemd est actif et stable.
Décision : Si vous voyez degraded, vérifiez les unités failed avant d’accuser Kubernetes de problèmes « aléatoires ».

Task 4: Confirmer la santé du runtime de conteneurs (exemple Docker)

cr0x@server:~$ docker info --format '{{.ServerVersion}} {{.CgroupVersion}}'
24.0.7 2

Signification de la sortie : Docker est joignable et rapporte la version de cgroup.
Décision : Si cette commande est lente ou bloque, corrigez Docker avant de toucher à kind/k3d.

Task 5: Mesurer rapidement la pression mémoire

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       5.9Gi       310Mi       160Mi       1.5Gi       1.3Gi
Swap:          4.0Gi       1.2Gi       2.8Gi

Signification de la sortie : available compte plus que free. L’utilisation du swap indique une pression.
Décision : Si available est < ~1Gi et que le swap augmente, réduisez le cluster, baissez les limites ou augmentez la mémoire WSL.

Task 6: Vérifier l’usage disque là où ça compte

cr0x@server:~$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb       250G  180G   71G  72% /

Signification de la sortie : C’est votre système de fichiers de distribution soutenu par VHDX.
Décision : Au‑dessus de ~85% d’utilisation, les performances et le comportement de compaction se dégradent. Prunez images et PVs anciens.

Task 7: Installer et créer un cluster kind avec des valeurs par défaut sensées

cr0x@server:~$ kind create cluster --name dev --image kindest/node:v1.29.2
Creating cluster "dev" ...
 ✓ Ensuring node image (kindest/node:v1.29.2) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-dev"
You can now use your cluster with:

kubectl cluster-info --context kind-dev

Signification de la sortie : Cluster créé, contexte défini. StorageClass installé (généralement standard).
Décision : Si l’installation du CNI bloque, suspectez DNS/proxy/VPN ou problèmes de pull d’images — ne relancez pas aveuglément.

Task 8: Vérifier la vivacité du cluster et la santé des composants

cr0x@server:~$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:40685
CoreDNS is running at https://127.0.0.1:40685/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
cr0x@server:~$ kubectl get nodes -o wide
NAME                STATUS   ROLES           AGE   VERSION   INTERNAL-IP   OS-IMAGE
dev-control-plane   Ready    control-plane   2m    v1.29.2   172.18.0.2    Debian GNU/Linux 12 (bookworm)

Signification de la sortie : API server joignable, nœud Ready, IP interne assignée.
Décision : Si le nœud est NotReady, passez directement à kubectl describe node et aux logs CNI — ne réinstallez pas tout immédiatement.

Task 9: Repérer les vrais gloutons de ressources (nœuds + pods)

cr0x@server:~$ kubectl top nodes
NAME                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
dev-control-plane   620m         15%    2240Mi          56%

Signification de la sortie : Metrics‑server fonctionne (kind l’inclut souvent via des addons ou vous l’avez installé).
Décision : Si la mémoire est élevée à l’arrêt, vérifiez les controllers bavards, les builds en fuite ou un expéditeur de logs bloqué.

Task 10: Valider le DNS dans le cluster (test fumée bon marché)

cr0x@server:~$ kubectl run -it --rm dns-test --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default.svc.cluster.local
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default.svc.cluster.local
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
pod "dns-test" deleted

Signification de la sortie : CoreDNS répond, la découverte de services fonctionne.
Décision : Si cela timeoute, corrigez le DNS avant de déboguer votre app. Votre application est innocente jusqu’à preuve du contraire.

Task 11: Confirmer si kubectl lent est dû au réseau ou à la latence API

cr0x@server:~$ time kubectl get pods -A
NAMESPACE     NAME                                        READY   STATUS    RESTARTS   AGE
kube-system   coredns-76f75df574-2lq9r                    1/1     Running   0          4m
kube-system   coredns-76f75df574-9x2ns                    1/1     Running   0          4m
kube-system   etcd-dev-control-plane                      1/1     Running   0          4m
kube-system   kindnet-4cdbf                               1/1     Running   0          4m
kube-system   kube-apiserver-dev-control-plane            1/1     Running   0          4m
kube-system   kube-controller-manager-dev-control-plane   1/1     Running   0          4m
kube-system   kube-proxy-4xw26                            1/1     Running   0          4m
kube-system   kube-scheduler-dev-control-plane            1/1     Running   0          4m

real    0m0.312s
user    0m0.127s
sys     0m0.046s

Signification de la sortie : 300ms est acceptable en local. Plusieurs secondes suggèrent DNS, confusion de contexte kubeconfig, ou un API server en difficulté.
Décision : Si c’est lent, lancez kubectl get --raw /readyz?verbose ensuite.

Task 12: Vérifier les endpoints readiness de l’API server pour trouver le réel blocage

cr0x@server:~$ kubectl get --raw='/readyz?verbose'
[+]ping ok
[+]log ok
[+]etcd ok
[+]informer-sync ok
[+]poststarthook/start-apiserver-admission-initializer ok
[+]poststarthook/start-apiextensions-informers ok
[+]poststarthook/start-apiextensions-controllers ok
readyz check passed

Signification de la sortie : Si etcd ou informer sync est lent/échoue, le plan de contrôle est le goulot.
Décision : etcd lent signifie souvent latence stockage. C’est votre signal pour vérifier le disque et éviter l’I/O cross‑filesystem.

Task 13: Trouver le pod qui brûle votre portable (CPU/mémoire)

cr0x@server:~$ kubectl top pods -A --sort-by=memory | tail -n 10
default       api-7b7c7d8f6c-9bq5m             1/1     980Mi
observability prometheus-0                      2/2     1210Mi
observability loki-0                            1/1     1530Mi

Signification de la sortie : Vous voyez les plus gros consommateurs.
Décision : Si votre cluster de dev inclut Prometheus/Loki par défaut, vous venez de trouver la réponse « pourquoi il fait chaud ? ».
Réduisez l’échelle, diminuez la rétention ou utilisez des outils plus légers en local.

Task 14: Vérifier l’utilisation disque du runtime de conteneurs (Docker)

cr0x@server:~$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          42        12        18.4GB    12.1GB (65%)
Containers      19        6         1.2GB     720MB (60%)
Local Volumes   27        9         9.8GB     6.3GB (64%)
Build Cache     124       0         22.6GB    22.6GB

Signification de la sortie : Le build cache est souvent le consommateur silencieux de disque.
Décision : Si la part reclaimable est grande, prunez délibérément. N’attendez pas que votre VHDX atteigne 95% et que tout ralentisse.

Task 15: Pruner en sécurité (et accepter le compromis)

cr0x@server:~$ docker builder prune --all --force
Deleted build cache objects:
v8m3q8qgk7yq4o0l5u3f7s1m2
...
Total reclaimed space: 22.6GB

Signification de la sortie : Vous avez récupéré de l’espace, au prix de reconstruire des couches plus tard.
Décision : En dev, l’espace disque et la stabilité valent mieux que gagner 90 secondes sur le prochain build.

Task 16: Confirmer que vous n’exécutez pas accidentellement des workloads sur /mnt/c

cr0x@server:~$ kubectl get pv -A -o wide
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS   REASON   AGE   VOLUMEMODE
pvc-1d2c7f7e-2f5d-4c0d-9a3a-2c6f9d8b1a7c   10Gi       RWO            Delete           Bound    default/db-data           standard                8m    Filesystem

Signification de la sortie : Cela n’affiche pas le chemin hôte. Dans kind, local‑path et le provisioner par défaut diffèrent.
Décision : Inspectez la storage class et le comportement du provisioner ; si ça bind sur hostPath vers un chemin monté Windows, corrigez‑le immédiatement.

Task 17: Diagnostiquer kubelet/container via les logs du nœud (container du nœud kind)

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Status}}' | grep dev-control-plane
dev-control-plane   Up 6 minutes
cr0x@server:~$ docker logs dev-control-plane | tail -n 20
I0205 09:10:12.123456       1 server.go:472] "Kubelet version" kubeletVersion="v1.29.2"
I0205 09:10:15.234567       1 kubelet.go:2050] "Skipping pod synchronization" error="PLEG is not healthy"
...

Signification de la sortie : Si PLEG est unhealthy, le kubelet peine — souvent à cause d’E/S disque ou de lenteur du runtime conteneur.
Décision : Vérifiez la latence disque, la santé du runtime conteneur et le niveau de churn des logs.

Task 18: Vérification rapide des tempêtes de logs (elles peuvent être votre workload le plus chaud)

cr0x@server:~$ kubectl logs -n kube-system deploy/coredns --tail=20
.:53
[INFO] plugin/reload: Running configuration SHA512 = 7a9b...
[INFO] 10.244.0.1:52044 - 46483 "A IN kubernetes.default.svc.cluster.local. udp 62 false 512" NOERROR qr,aa,rd 114 0.000131268s

Signification de la sortie : Quelques logs DNS sont normaux. Des milliers par seconde ne le sont pas.
Décision : Si les logs sont chauds, réduisez la verbosité, corrigez la boucle de retry du client, sinon vous paierez en CPU et en écritures disque.

Trois mini‑histoires d’entreprise issues du terrain

Mini‑histoire 1 : L’incident causé par une mauvaise hypothèse

Une équipe avec laquelle j’ai travaillé avait standardisé WSL2 pour les clusters dev car c’était « à peu près Linux ».
Ils gardaient leur repo sur le système de fichiers Windows pour une intégration IDE facile, puis le montaient dans des conteneurs pour les builds et tests.
Ça semblait correct pour de petits services. Puis l’équipe plateforme a ajouté un Postgres local, un controller et une suite de tests lançant des migrations à chaque exécution.

Le symptôme était étrange : les migrations prenaient parfois 30 secondes, parfois 10 minutes.
Les gens accusaient « l’overhead Kubernetes » et « cet operator qu’on a ajouté ».
Un ingénieur a essayé d’y remédier en augmentant les limites CPU. Ça a empiré — plus de CPU a juste fait atteindre plus vite le goulot stockage.

La mauvaise hypothèse était simple : ils pensaient que /mnt/c était « juste un autre système de fichiers ».
Ce n’est pas le cas. C’est une frontière avec un comportement de cache différent, des performances métadonnées différentes et des sémantiques de flush différentes.
Leur volume de base de données et leurs caches de build étaient sur le chemin lent.

La correction fut peu flatteuse : déplacer la base et le cache de build dans le système de fichiers Linux, et ne garder le checkout source sur Windows que si nécessaire.
Ils ont aussi ajouté un script preflight qui refusait de démarrer la stack s’il détectait des PV pointant vers /mnt/c.
Les performances se sont stabilisées instantanément. Personne n’a fait la fête — c’est souvent le signe d’une bonne correction.

Mini‑histoire 2 : L’optimisation qui a mal tourné

Une autre entreprise voulait des « clusters locaux plus rapides », ils ont donc préchargé tout : stack observabilité, ingress, cert‑manager et quelques operators.
L’idée était noble : réduire le temps d’onboarding, s’assurer que tout le monde ait la même base, éviter « ça marche sur mon portable ».
Ils ont même construit un script interne qui créait le cluster et installait tous les charts en une fois.

Puis les tickets ont commencé. Les portables chauffaient pendant les réunions. L’autonomie chutait.
kubectl mettait parfois plusieurs secondes. Les développeurs ont commencé à désactiver des composants « temporairement », ce qui est vite devenu une dérive permanente.
L’équipe plateforme a réagi en poussant plus de limites par défaut et plus de réplicas, pour « parité prod ».

Le retour de bâton venait du churn des controllers et du travail en arrière‑plan.
Le scraping Prometheus, l’ingestion Loki, la reconciliation de cert‑manager et les boucles d’operator ne sont pas gratuits.
Dans un vrai cluster, on amortit ce coût sur des serveurs. Sur un portable, vous le sentez à chaque accélération de ventilateur.

La correction fut de définir deux profils : core (ingress + DNS + storage + metrics‑server) et full (la pile lourde).
Core est par défaut ; full est opt‑in pour le debug.
Ils ont aussi réduit les intervalles de scraping et la rétention en mode local. L’ironie : l’onboarding a été plus rapide parce que les gens ont arrêté de lutter contre leur environnement.

Mini‑histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une entreprise régulée (du genre qui adore les tableurs) avait une expérience WSL2 Kubernetes remarquablement lisse.
Leur secret n’était pas une chaîne d’outils fancy. C’était la discipline : verrouillage de versions, création de cluster reproductible et nettoyage agressif.
Chaque développeur avait la même image kind node, les mêmes versions de charts et les mêmes limites par défaut.

Ils avaient aussi une routine de maintenance hebdomadaire : prune des images inutilisées, suppression des namespaces inutiles et compaction de l’environnement dev quand nécessaire.
C’était planifié, documenté et ennuyeux.
Les développeurs se sont plaints au début — personne n’aime une « journée maintenance » sur son portable.

Puis un jour une mise à jour Windows a modifié quelque chose de subtil dans le réseau.
La moitié des clusters de l’organisation a commencé à avoir des pannes DNS intermittentes.
Les équipes avec des environnements dérivés ont eu un gros bazar : versions CNI différentes, kubeconfigs aléatoires, overrides DNS locaux incohérents.
Les équipes disciplinées pouvaient reproduire rapidement et comparer à l’identique.

Elles l’ont isolé au comportement des resolvers sous VPN, ont déployé un contournement standardisé et sont retournées travailler.
La pratique ennuyeuse a sauvé la mise : versions cohérentes et baselines identiques rendent le débogage fini et rapide.

Procédure de diagnostic rapide : quoi vérifier en premier, second, troisième

Quand votre portable fond ou que votre cluster est « lent », vous n’avez pas le temps d’admirer l’architecture.
Vous avez besoin d’un chemin déterministe vers le goulot.

Premier : L’hôte (Windows + WSL2) est‑il sous pression de ressources ?

  1. Vérifier l’utilisation mémoire et swap WSL2 : free -h. Si available est bas et le swap augmente, vous êtes limité par la mémoire.
  2. Vérifier le remplissage disque : df -h /. Si proche du plein, tout devient plus lent et fragile.
  3. Vérifier rapidement l’intégrité I/O : dd ... conv=fdatasync sur le FS Linux vs /mnt/c. Si le FS Linux est aussi lent, vous avez une pression I/O au niveau système.

Second : Le plan de contrôle Kubernetes est‑il sain ou bloqué ?

  1. API readyz : kubectl get --raw='/readyz?verbose'. Si les checks etcd sont lents, suspectez la latence stockage.
  2. Statut des nœuds : kubectl get nodes et kubectl describe node. Si NotReady, regardez les symptômes CNI et kubelet.
  3. Test fumée CoreDNS : lancez un nslookup depuis busybox. Si le DNS est cassé, arrêtez de faire semblant que l’app est le problème.

Troisième : Quel workload brûle réellement CPU/mémoire/E/S ?

  1. Gros consommateurs : kubectl top pods -A --sort-by=memory et --sort-by=cpu.
  2. Tempêtes de logs : vérifiez les logs des pods suspects. Taux d’écriture élevé = pression I/O = ralentissement global.
  3. Churn image/build : docker system df et prune du build cache si ça a gonflé.

Idée paraphrasée de Werner Vogels : « Tout échoue, tout le temps. » Construisez votre setup local pour que l’échec soit rapide à identifier, pas mystérieux.

Erreurs courantes : symptôme → cause racine → correction

1) Symptom : Les ventilateurs du portable s’emballent quand le cluster est « idle »

Cause racine : controllers en arrière‑plan (stack d’observabilité, operators) qui effectuent une reconciliation constante ; ou un pod en crash loop qui écrit des logs.

Correction : kubectl top pods -A, trouvez le glouton ; scale down ; réduisez la rétention/intervalles de scrape ; corrigez les crash loops ; définissez des requests/limits sensés.

2) Symptom : kubectl prend 5–30 secondes aléatoirement

Cause racine : timeouts DNS ou interférence de resolvers VPN ; parfois kubeconfig pointe vers un contexte mort.

Correction : lancez time kubectl get pods -A, puis kubectl get --raw='/readyz?verbose'. Si readyz est OK, testez le DNS dans le cluster. Si le DNS échoue, corrigez resolv.conf/politiques split DNS du VPN ou travaillez hors VPN pour les tâches locales.

3) Symptom : Postgres/MySQL dans le cluster est affreusement lent

Cause racine : PV ou bind mounts sur /mnt/c ou autre frontière lente ; workloads fsync‑heavy l’amplifient.

Correction : conservez les données PV sur le système de fichiers Linux ; utilisez un provisioner local‑path qui écrit dans /var à l’intérieur de WSL, pas sur des montages Windows.

4) Symptom : WSL2 mange de la RAM et ne la rend jamais

Cause racine : page cache Linux + comportement de récupération WSL2 ; gros builds et pulls d’images remplissent le cache ; limite mémoire non configurée.

Correction : définissez un plafond dans .wslconfig ; redémarrez WSL avec wsl.exe --shutdown quand nécessaire ; réduisez l’empreinte du cluster et évitez d’exécuter tout en même temps.

5) Symptom : Le disque se remplit « mystérieusement »

Cause racine : couches d’images conteneurs, build cache, données PV restantes et logs ; VHDX qui grossit ; absence de prune.

Correction : docker system df et docker builder prune --all ; supprimez namespaces/PVs inutilisés ; surveillez df -h.

6) Symptom : Nœud devient NotReady ; pods bloqués en ContainerCreating

Cause racine : CNI cassé ou kubelet/runtime conteneur en difficulté à cause de la pression I/O ; container du nœud kind unhealthy.

Correction : vérifiez les logs du container du nœud kind ; vérifiez les pods CNI dans kube-system ; corrigez la pression disque ; recréez le cluster si l’image du nœud est corrompue.

7) Symptom : L’ingress fonctionne depuis WSL mais pas depuis Windows

Cause racine : attentes de forwarding des ports erronées ; pare‑feu Windows/VPN ; confusion entre IP WSL et localhost Windows.

Correction : décidez d’une méthode d’accès (localhost forwardé vs IP VM WSL) ; documentez‑la ; exposez l’ingress avec un mapping prévisible ; vérifiez avec curl des deux côtés.

8) Symptom : Les builds dans des conteneurs sont plus lents que sur Windows

Cause racine : arbre source sur le montage Windows ; opérations métadonnées lourdes à travers la frontière ; antivirus scannant le chemin Windows.

Correction : gardez la source dans le système de fichiers Linux pour les builds ; utilisez l’IDE Windows via l’intégration WSL ; excluez les répertoires de build de l’AV Windows si la politique le permet.

Seconde et dernière petite blague : Si votre cluster dev a besoin d’un runbook, bravo — vous avez construit un petit environnement de production avec un pire financement.

Checklists / plan étape par étape

Plan d’installation (faire une fois par portable)

  1. Définir les limites WSL2 dans .wslconfig : plafonner mémoire et CPU ; activer un swap raisonnable.
  2. Activer systemd dans WSL (si supporté) et standardiser cela dans votre équipe.
  3. Choisir un runtime : Docker Engine dans WSL2 est bien ; évitez de mélanger Docker Desktop + Docker WSL sauf si vous aimez l’ambiguïté.
  4. Choisir un outil Kubernetes : kind (recommandé) ou k3d. Choisissez‑en un et standardisez les scripts de création de cluster.
  5. Garder les données du cluster sur le FS Linux : assurez‑vous que le stockage du runtime et les chemins PV ne sont pas sur /mnt/c.
  6. Définir des profils : « core » par défaut ; « full » opt‑in. Votre portable n’est pas un cluster de staging.
  7. Verrouiller les versions : image kind node, versions de charts et addons critiques.

Checklist workflow quotidien (rester rapide, rester sain)

  1. Avant un gros travail : free -h et df -h /. Si vous êtes bas, prunez d’abord.
  2. Après une grosse journée de builds : docker system df. Si le build cache est énorme, prunez‑le.
  3. Quand quelque chose paraît lent : lancez le test fumée DNS et les checks /readyz avant de changer quoi que ce soit.
  4. Gardez votre repo là où vos outils sont les plus rapides : si les builds se font en Linux, conservez la copie de travail en Linux.

Checklist maintenance hebdomadaire (ennuyeux, efficace)

  1. Pruner le build cache : docker builder prune --all.
  2. Pruner images et containers inutilisés : docker system prune (attention : comprendre ce que ça supprime).
  3. Supprimer namespaces et PVs inutilisés dans le cluster dev.
  4. Recréer le cluster s’il a accumulé trop de dérive. Le teardown est une fonctionnalité.
  5. Récupérer la mémoire si Windows est serré : wsl.exe --shutdown.

FAQ

1) Dois‑je utiliser Docker Desktop ou Docker Engine dans WSL2 ?

Si vous voulez l’intégration Windows la plus simple et que votre entreprise la standardise, Docker Desktop est acceptable.
Si vous voulez moins de pièces en mouvement et un comportement Linux plus clair, utilisez Docker Engine dans WSL2.
Choisissez‑en un et engagez‑vous ; les setups mixtes créent du folklore de débogage.

2) Pourquoi stocker des données sur /mnt/c pose‑t‑il problème ?

Parce que vous franchissez une frontière virtualisation/interop avec des sémantiques de cache et de métadonnées différentes.
Les bases de données effectuent beaucoup de petites écritures et d’appels fsync. Ce chemin les punit.
Gardez les I/O lourdes dans le FS Linux et considérez /mnt/c comme « bon pour les documents, pas pour les données chaudes ».

3) kind ou k3d : lequel est le moins susceptible de faire fondre mon portable ?

k3d utilise souvent moins de mémoire de base parce que k3s est plus petit.
kind est extrêmement prévisible et simple à verrouiller en version. Les deux peuvent être sûrs pour un portable si vous gardez les workloads légers et fixez des limites WSL2.
Ma préférence : kind pour le travail sur plateforme et la simulation multi‑nœuds ; k3d pour « juste exécuter la stack ».

4) Combien de RAM dois‑je allouer à WSL2 ?

Sur 16Go total : 6–8Go est un bon plafond.
Sur 32Go : 12–16Go est approprié.
Si vous allouez trop, vous masquez de mauvais limits de pods et affamez subtilement les apps Windows.

5) Pourquoi WSL2 conserve‑t‑il la mémoire après avoir arrêté des workloads ?

Linux utilise agressivement la mémoire pour le cache de fichier. C’est normalement une bonne chose.
La restitution de cette mémoire par WSL2 vers Windows peut être plus lente que souhaitée.
Si vous avez besoin de RAM immédiatement, arrêtez WSL ; si vous voulez de la sérénité à long terme, contraignez la mémoire et réduisez le churn en arrière‑plan.

6) Pourquoi mes commandes kubectl sont lentes seulement quand le VPN est activé ?

Les clients VPN injectent souvent des resolvers DNS et des règles de routage.
Kubernetes repose sur le DNS en interne, et kubectl sur une connectivité fiable vers le endpoint API.
Diagnosez avec le test fumée DNS et les checks readyz ; puis décidez de split‑tunnel, d’ajustements des resolvers ou de travailler hors VPN pour les tâches locales.

7) Comment exposer des services vers Windows depuis un cluster tournant dans WSL2 ?

Décidez si vous utilisez des ports localhost forwardés ou l’IP de la VM WSL.
Pour une UX dev prévisible, beaucoup d’équipes font du port‑forward (kubectl port‑forward) ou exécutent un ingress mappé sur des ports connus.
Documentez la méthode afin que votre équipe n’aille pas déboguer « localhost » pour le plaisir.

8) Puis‑je exécuter des workloads stateful (Postgres, Kafka) localement dans WSL2 Kubernetes ?

Oui, mais soyez réaliste. Postgres convient pour le dev si ses données résident sur le FS Linux et que vous n’exécutez pas cinq autres piles lourdes.
Kafka est possible, mais c’est souvent là que la « parité locale » devient « punition locale ». Envisagez des substituts plus légers sauf si vous debuggez un comportement Kafka spécifique.

9) À quelle fréquence dois‑je recréer mon cluster local ?

Si vous faites du travail plateforme avec beaucoup de CRDs et d’installations de controllers, recréer hebdomadairement ou bi‑hebdomadairement est normal.
Si votre cluster est stable et léger, vous pouvez le garder plus longtemps.
Recréez immédiatement dès que vous suspectez de la dérive : DNS étrange, webhooks bloqués ou échecs d’admission mystérieux.

10) Quelle est la cause la plus fréquente de « tout est lent » ?

Le stockage. Soit le workload est sur le mauvais chemin de FS, soit le disque est presque plein, soit le système écrit des logs comme si on payait au nombre de lignes.
La mémoire arrive en second. Le DNS en troisième. Kubernetes lui‑même est rarement la cause première ; il n’est que la scène où le problème se joue.

Prochaines étapes que vous pouvez faire aujourd’hui

  1. Définissez vos limites WSL2 (mémoire, CPU, swap). Si vous ne faites qu’une chose, faites‑cela.
  2. Déplacez les données chaudes hors de /mnt/c : stockage runtime, PVs, bases, caches de build — gardez‑les sur le FS Linux.
  3. Choisissez un profil cluster léger par défaut : kind ou k3d avec seulement les addons core. Faites du « full stack » un profil opt‑in.
  4. Adoptez la procédure de diagnostic rapide : vérifiez la pression hôte, puis la santé du plan de contrôle, puis les plus gros consommateurs. Arrêtez de deviner.
  5. Planifiez la maintenance ennuyeuse : prune des caches, suppression des namespaces inutiles et recréation du cluster quand la dérive s’installe.

L’objectif final n’est pas de construire le cluster local le plus impressionnant. C’est d’en construire un qui se comporte de manière cohérente sous contrainte.
La prévisibilité est ce qui garde votre portable au frais — et votre cerveau aussi.

← Précédent
Industrie informatique : le mythe du « réécrire depuis zéro » — pourquoi ça échoue et ce qui marche
Suivant →
Craquements audio sur Windows 11 : corriger la latence sans acheter de nouveau matériel

Laisser un commentaire