Le cluster tourne, le stockage est répliqué. Reste la question qui bloque tous les Kubernetes auto-hébergés : comment un utilisateur atteint-il une application ? Chez un fournisseur cloud, demander un service de type LoadBalancer déclenche la création d'un équilibreur de charge et l'attribution d'une adresse publique. Sur une machine dans un salon, il ne se passe rien du tout — le service reste indéfiniment en attente.
Deux briques, deux rôles distincts
- MetalLB travaille au niveau réseau : il attribue une adresse IP au cluster et la fait exister sur le réseau local.
- Traefik travaille au niveau HTTP : il reçoit tout le trafic arrivant sur cette adresse et le distribue selon le nom de domaine demandé.
Le premier donne une porte d'entrée, le second sait à quel appartement livrer. Les deux sont nécessaires.
MetalLB : une adresse IP qui appartient au cluster
K3S embarque un équilibreur simplifié — Klipper, ou servicelb — qui suffit à un nœud unique mais ne fournit pas d'adresse flottante. On le désactive proprement, sur les trois nœuds :
# /etc/rancher/k3s/config.yaml disable: - servicelb
systemctl restart k3s
Puis on déploie MetalLB et on lui confie une plage d'adresses prise en dehors du pool DHCP — c'est le point à ne pas rater, sous peine de conflit d'adresses parfaitement invisible jusqu'au jour où il ne l'est plus :
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: pool-labk3s namespace: metallb-system spec: addresses: - 192.168.50.230-192.168.50.250 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: l2-labk3s namespace: metallb-system spec: ipAddressPools: - pool-labk3s
Le mode Layer 2, en une phrase
Un des nœuds annonce l'adresse sur le réseau local — il répond aux requêtes ARP qui la concernent, comme s'il la portait. Tout le trafic destiné à cette adresse arrive donc sur ce nœud, qui le distribue ensuite dans le cluster. Si le nœud tombe, un autre reprend l'annonce en quelques secondes.
Ce n'est pas de la répartition de charge au sens strict — un seul nœud reçoit le trafic à un instant donné — mais c'est de la haute disponibilité : l'adresse survit à la perte d'une machine. Pour un lab comme pour beaucoup de petites infrastructures, c'est exactement ce qu'il faut. La répartition réelle demanderait du BGP, que MetalLB sait aussi faire.
Traefik : une adresse, tous les services
Traefik est déjà là : K3S l'installe par défaut comme contrôleur d'entrée. Il suffit de lui fixer l'adresse fournie par MetalLB, plutôt que de le laisser en prendre une au hasard dans la plage :
kubectl -n kube-system annotate svc traefik \ metallb.universe.tf/loadBalancerIPs="192.168.50.250" --overwrite

Une seule adresse IP en entrée, un routage par nom d'hôte en sortie : c'est tout le principe de l'Ingress.
Le wildcard DNS : la ligne qui change tout
Vient alors le geste le plus rentable de tout le lab. Dans la zone DNS de la passerelle, une seule ligne :
*.cluster IN A 192.168.50.250
Sans oublier d'incrémenter le numéro de série de la zone, puis :
named-checkzone labk3s.ev1 /etc/bind/zones/db.labk3s.ev1 systemctl reload bind9
À partir de cet instant, tout nom en *.cluster.labk3s.ev1 — y compris ceux qui n'existent pas encore — pointe vers le cluster. Déployer une nouvelle application ne demandera plus jamais de toucher au DNS : c'est l'Ingress qui déclare le nom, et il fonctionne immédiatement.
Le test qui valide la chaîne
Un déploiement minimal, un service, un Ingress :
kubectl create deployment web --image=nginx kubectl expose deployment web --port 80
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: nginx.cluster.labk3s.ev1
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
curl -I http://nginx.cluster.labk3s.ev1 HTTP/1.1 200 OK Server: nginx/1.29.4
Ce 200 OK valide d'un coup toute la chaîne : la résolution DNS wildcard, l'annonce de l'adresse par MetalLB, le routage par nom dans Traefik, et le service jusqu'au conteneur. Si quelque chose cloche, on peut d'ailleurs court-circuiter le DNS pour isoler la panne :
curl -I -H "Host: nginx.cluster.labk3s.ev1" http://192.168.50.250
Une réponse correcte ici mais pas avec le nom : le problème est dans le DNS. Une erreur dans les deux cas : il est dans le cluster.
Le tableau de bord de Traefik

Le tableau de bord montre les points d'entrée, les routeurs déclarés et l'état des services — pratique pour comprendre pourquoi une route ne prend pas.
Traefik expose un tableau de bord qui liste les points d'entrée, les routeurs issus des Ingress et les services associés. En lab, il s'expose comme n'importe quelle autre application. En production, certainement pas : il révèle toute la topologie de routage et doit rester sur une interface réservée, derrière une authentification forte.
Ce qui est acquis à ce stade
Le cluster a une adresse d'entrée stable, résistante à la perte d'un nœud, et un domaine entier qui pointe dessus. Déployer une application se résume désormais à écrire un fichier YAML — c'est l'objet du dernier article.
Le pas à pas détaillé est sur le wiki
Cet article ne remplace pas la documentation : il en explique les choix. L'intégralité de la démarche — commandes, sorties d'écran, vérifications et captures — est publiée sur mon wiki, dans la section Datacenter / Cluster K3S. Pages correspondant à cet article :
- 6. Configuration du load balancer MetalLB
- 7. Reverse proxy Traefik et wildcard DNS
- 11. Dashboard Traefik
La série « Lab Kubernetes maison »
Cet article fait partie d'une série qui monte, pas à pas, un cluster Kubernetes complet sur une seule machine physique :