
Ce guide vous permet de créer un cluster Kubernetes local en 20 secondes avec k3d. Vous apprendrez à démarrer un cluster single-node, multi-nœuds avec workers, un cluster HA (haute disponibilité) avec 3 control-planes et etcd embarqué, et à utiliser un registre d’images local intégré. Toutes les commandes ont été testées avec k3d v5.8.3 et k3s v1.31.5.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer k3d et créer votre premier cluster en une commande
- Déployer un cluster multi-nœuds (servers + agents)
- Configurer un cluster HA avec 3 control-planes et etcd distribué
- Importer des images Docker locales dans le cluster
- Créer un registre d’images local intégré au cluster
- Exposer des services via Ingress (Traefik intégré) ou NodePort
- Utiliser un fichier de configuration YAML pour vos clusters
Quand choisir k3d
Section intitulée « Quand choisir k3d »k3d n’est pas le seul outil pour créer un cluster Kubernetes local. Voici un comparatif pour vous aider à choisir :
| Critère | k3d | Minikube | Kind |
|---|---|---|---|
| Cas d’usage | Dev local, CI/CD, clusters jetables | Dev local, apprentissage | CI/CD, tests |
| Runtime | Conteneurs Docker (k3s) | VM ou conteneurs | Conteneurs Docker (kubeadm) |
| Datastore | SQLite (1 server) / etcd embarqué (HA) | etcd (kubeadm) | etcd (kubeadm) |
| Multi-nœuds | ✅ --servers + --agents | ✅ --nodes | ✅ via config YAML |
| HA control plane | ✅ --servers 3 (etcd embarqué) | ✅ --ha (kube-vip) | ✅ multi control-planes |
| Ingress | ✅ Traefik intégré | ⚠️ Addon à activer | ⚠️ À installer |
| Registre local | ✅ --registry-create (intégré) | ⚠️ Addon cassé (v1.37) | ⚠️ Manuel |
| Démarrage | ~15-20s | ~30-60s | ~20-30s |
| Ressources | Léger (~300 MiB/nœud) | 2 CPU, 2 Go RAM/nœud | ~500 MiB/nœud |
| Config as Code | ✅ Fichier YAML | ⚠️ Flags CLI | ✅ Fichier YAML |
Choisissez k3d si :
- Vous voulez le cluster Kubernetes le plus rapide à créer et détruire
- Vous avez besoin d’un registre d’images local sans configuration manuelle
- Vous travaillez avec des pipelines CI/CD qui nécessitent des clusters éphémères
- Vous voulez Traefik comme Ingress Controller prêt à l’emploi
Comment fonctionne k3d
Section intitulée « Comment fonctionne k3d »Comprendre l’architecture de k3d vous aidera à diagnostiquer les problèmes et à choisir la bonne topologie.
k3d crée des conteneurs Docker qui exécutent chacun une instance de k3s. Contrairement à Minikube qui peut utiliser des VMs, k3d utilise exclusivement Docker (ou Podman) comme runtime. C’est ce qui le rend si rapide à démarrer.
Architecture d’un cluster k3d
Section intitulée « Architecture d’un cluster k3d »Quand vous créez un cluster avec k3d cluster create, voici ce qui se passe :
- Un réseau Docker dédié est créé pour isoler le cluster
- Un ou plusieurs conteneurs server (control-planes k3s) sont lancés
- Un ou plusieurs conteneurs agent (workers k3s) rejoignent le cluster
- Un load balancer (serverlb, basé sur Nginx) est créé devant les servers
- Le kubeconfig est automatiquement fusionné dans votre fichier par défaut
Points clés :
- Chaque nœud (server ou agent) est un conteneur Docker exécutant k3s
- Le load balancer
serverlbdistribue le trafic API vers tous les servers - Les ports exposés sur le
serverlbsont proxifiés vers les nœuds server - k3s utilise containerd comme runtime à l’intérieur des conteneurs
- Traefik est déployé automatiquement comme Ingress Controller
Un seul daemon Docker
Section intitulée « Un seul daemon Docker »Contrairement à Minikube (qui a un daemon Docker dans chaque nœud), k3d
utilise le daemon Docker de votre machine. Les nœuds tournent comme des
conteneurs classiques. Pour importer une image, k3d la copie directement
dans les conteneurs nœuds — pas besoin de docker-env ou de double daemon.
Prérequis
Section intitulée « Prérequis »Avant de commencer, vérifiez que vous avez :
- Docker installé et fonctionnel (v20.10.5 minimum) — Guide d’installation Docker
- kubectl installé — Guide kubectl
- RAM : ~512 Mo par nœud (2 Go recommandés pour un cluster HA)
- Disque : quelques Go pour les images Docker
Vérification :
docker version --format '{{.Server.Version}}'27.5.1kubectl version --client --short 2>/dev/null || kubectl version --clientInstaller k3d
Section intitulée « Installer k3d »curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bashbrew install k3dchoco install k3dOu via Scoop :
scoop install k3dVérification :
k3d versionk3d version v5.8.3k3s version v1.31.5-k3s1 (default)Démarrer un cluster single-node
Section intitulée « Démarrer un cluster single-node »Le cas le plus simple : un seul server (control-plane) qui sert aussi de worker.
k3d cluster create demo -p "8888:80@loadbalancer"| Option | Description |
|---|---|
demo | Nom du cluster (sera préfixé k3d- dans Docker) |
-p "8888:80@loadbalancer" | Mappe le port 8888 local vers le port 80 du load balancer |
Le cluster est prêt en 15 à 20 secondes. k3d configure automatiquement votre kubeconfig pour utiliser ce cluster.
Vérification :
kubectl get nodes -o wideNAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGEk3d-demo-server-0 Ready control-plane,master 15s v1.31.5+k3s1 172.21.0.2 K3s v1.31.5+k3s1k3d cluster listNAME SERVERS AGENTS LOADBALANCERdemo 1/1 0/0 truePour voir les conteneurs Docker créés :
docker ps --filter "name=k3d-demo" --format "table {{.Names}}\t{{.Image}}"NAMES IMAGEk3d-demo-serverlb ghcr.io/k3d-io/k3d-proxy:5.8.3k3d-demo-server-0 rancher/k3s:v1.31.5-k3s1Cluster multi-nœuds (servers + agents)
Section intitulée « Cluster multi-nœuds (servers + agents) »Pour simuler un environnement plus réaliste avec un control-plane et des workers dédiés :
k3d cluster create multinode --servers 1 --agents 2 -p "8888:80@loadbalancer"Cette commande crée :
- 1 server (control-plane k3s,
k3d-multinode-server-0) - 2 agents (workers k3s,
k3d-multinode-agent-0,k3d-multinode-agent-1) - 1 load balancer (
k3d-multinode-serverlb)
Vérification :
kubectl get nodes -o wideNAME STATUS ROLES AGE VERSIONk3d-multinode-server-0 Ready control-plane,master 17s v1.31.5+k3s1k3d-multinode-agent-0 Ready <none> 16s v1.31.5+k3s1k3d-multinode-agent-1 Ready <none> 16s v1.31.5+k3s1Ajouter un agent à un cluster existant
Section intitulée « Ajouter un agent à un cluster existant »k3d node create extra-agent --cluster multinode --role agentSupprimer un nœud
Section intitulée « Supprimer un nœud »k3d node delete k3d-extra-agent-0Cluster HA (haute disponibilité)
Section intitulée « Cluster HA (haute disponibilité) »Le mode HA crée un cluster avec 3 servers (control-planes), chacun exécutant une instance d’etcd embarqué (embedded etcd). Cette topologie est celle recommandée pour la production Kubernetes.
Fonctionnement
Section intitulée « Fonctionnement »- k3d démarre le premier server avec
--cluster-initpour activer le mode etcd distribué - Les servers suivants rejoignent le cluster etcd existant
- Le load balancer serverlb distribue les requêtes API entre les 3 servers
- Si un server tombe, les 2 restants maintiennent le quorum etcd
Créer un cluster HA
Section intitulée « Créer un cluster HA »k3d cluster create ha-demo --servers 3 --agents 2 -p "8888:80@loadbalancer"Le démarrage prend environ 50 secondes (chaque server est démarré séquentiellement pour garantir la convergence etcd).
Vérification :
kubectl get nodes -o wideNAME STATUS ROLES AGE VERSIONk3d-ha-demo-server-0 Ready control-plane,etcd,master 50s v1.31.5+k3s1k3d-ha-demo-server-1 Ready control-plane,etcd,master 38s v1.31.5+k3s1k3d-ha-demo-server-2 Ready control-plane,etcd,master 20s v1.31.5+k3s1k3d-ha-demo-agent-0 Ready <none> 18s v1.31.5+k3s1k3d-ha-demo-agent-1 Ready <none> 18s v1.31.5+k3s1k3d cluster listNAME SERVERS AGENTS LOADBALANCERha-demo 3/3 2/2 trueNotez le rôle etcd sur chaque nœud server : c’est le signe que le mode etcd embarqué distribué est actif.
Ajouter un server à un cluster existant
Section intitulée « Ajouter un server à un cluster existant »k3d node create extra-server --cluster ha-demo --role serverUtiliser un fichier de configuration
Section intitulée « Utiliser un fichier de configuration »Plutôt que de passer de nombreux flags CLI, k3d supporte les fichiers de configuration YAML. C’est la méthode recommandée pour les clusters reproductibles.
Syntaxe minimale
Section intitulée « Syntaxe minimale »apiVersion: k3d.io/v1alpha5kind: Simplemetadata: name: my-clusterservers: 1agents: 2k3d cluster create --config k3d-config.yamlExemple complet
Section intitulée « Exemple complet »apiVersion: k3d.io/v1alpha5kind: Simplemetadata: name: from-configservers: 1agents: 2ports: - port: 8888:80 nodeFilters: - loadbalancerregistries: create: name: registry.localhost host: "0.0.0.0" hostPort: "5111"options: k3d: wait: trueCe fichier crée un cluster avec :
- 1 server + 2 agents
- Le port 80 du Ingress Controller exposé sur le port 8888 local
- Un registre d’images local accessible sur
registry.localhost:5111
k3d cluster create --config k3d-config.yaml| Champ | Description |
|---|---|
apiVersion | Toujours k3d.io/v1alpha5 (version actuelle) |
kind | Simple (le seul type public pour l’instant) |
metadata.name | Nom du cluster |
servers / agents | Nombre de nœuds de chaque type |
ports | Mapping de ports (identique au flag -p) |
registries.create | Crée un registre local avec le cluster |
options.k3d.wait | Attend que le cluster soit prêt avant de rendre la main |
Autres options utiles du fichier de configuration
Section intitulée « Autres options utiles du fichier de configuration »apiVersion: k3d.io/v1alpha5kind: Simplemetadata: name: avanceservers: 1agents: 2volumes: - volume: /my/host/path:/mnt/data nodeFilters: - server:0env: - envVar: MY_VAR=my-value nodeFilters: - server:0options: k3s: extraArgs: - arg: "--disable=traefik" nodeFilters: - server:* k3d: disableLoadbalancer: false kubeconfig: updateDefaultKubeconfig: true switchCurrentContext: true| Option | Usage |
|---|---|
volumes | Monte un dossier local dans un nœud |
env | Injecte des variables d’environnement |
options.k3s.extraArgs | Passe des arguments à k3s (ex : désactiver Traefik) |
options.k3d.disableLoadbalancer | Supprime le load balancer serverlb |
options.kubeconfig | Contrôle la fusion du kubeconfig |
Charger des images locales
Section intitulée « Charger des images locales »Le problème : Vous avez buildé une image Docker sur votre machine, mais quand vous la déployez dans k3d, Kubernetes ne la trouve pas.
Pourquoi ? Les conteneurs k3s utilisent containerd (pas le daemon Docker de votre machine). Votre image existe dans Docker local, pas dans containerd.
Méthode 1 : k3d image import
Section intitulée « Méthode 1 : k3d image import »La commande k3d image import copie une image depuis Docker vers tous les
nœuds du cluster :
# Builder votre imagedocker build -t mon-app:v1 .
# Importer dans le cluster k3dk3d image import mon-app:v1 -c demoDéployer l’image :
apiVersion: v1kind: Podmetadata: name: test-localspec: containers: - name: app image: mon-app:v1 imagePullPolicy: Neverkubectl apply -f pod.yamlkubectl get pod test-localNAME READY STATUS RESTARTS AGEtest-local 1/1 Running 0 10sMéthode 2 : Registre local intégré (recommandé)
Section intitulée « Méthode 2 : Registre local intégré (recommandé) »k3d peut créer un registre d’images local (conteneur Docker registry) connecté au cluster. C’est la méthode la plus fiable car elle fonctionne exactement comme un registre distant.
-
Créer un cluster avec registre :
Fenêtre de terminal k3d cluster create demo --registry-create myregistry.localhost:0.0.0.0:5111Ou via fichier de configuration (voir la section précédente).
-
Taguer et pousser votre image :
Fenêtre de terminal docker tag nginx:alpine myregistry.localhost:5111/nginx:latestdocker push myregistry.localhost:5111/nginx:latest -
Déployer depuis le registre :
Fenêtre de terminal kubectl run web --image=myregistry.localhost:5111/nginx:latestFenêtre de terminal kubectl get pod webNAME READY STATUS RESTARTS AGEweb 1/1 Running 0 10s
Le registre est accessible à la fois depuis votre machine locale (via
localhost:5111) et depuis les nœuds k3d (via le nom du conteneur sur le
réseau Docker).
Quand utiliser image import vs registre local ?
| Méthode | Cas d’usage |
|---|---|
k3d image import | Tests rapides, images uniques, pas de push nécessaire |
| Registre local | Workflow de développement continu, images partagées, CI/CD |
Exposer des services
Section intitulée « Exposer des services »k3d utilise un load balancer (serverlb) basé sur Nginx devant les nœuds
servers. Les ports que vous mappez à la création du cluster (-p) sont
routés via ce load balancer.
Via Ingress (recommandé)
Section intitulée « Via Ingress (recommandé) »k3s inclut Traefik comme Ingress Controller par défaut. Pas d’add-on à activer — tout est prêt.
-
Créer le cluster avec le port Ingress mappé :
Fenêtre de terminal k3d cluster create demo -p "8888:80@loadbalancer" --agents 2Le mapping
-p "8888:80@loadbalancer"signifie : “envoyer le trafic du port 8888 de ma machine vers le port 80 du load balancer, qui le forwarde vers Traefik dans les nœuds server”. -
Déployer une application :
Fenêtre de terminal kubectl create deployment nginx --image=nginx:alpinekubectl create service clusterip nginx --tcp=80:80 -
Créer un Ingress :
ingress.yaml apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: nginxannotations:ingress.kubernetes.io/ssl-redirect: "false"spec:rules:- http:paths:- path: /pathType: Prefixbackend:service:name: nginxport:number: 80Fenêtre de terminal kubectl apply -f ingress.yaml -
Tester l’accès :
Fenêtre de terminal curl http://localhost:8888/<!DOCTYPE html><html><head><title>Welcome to nginx!</title>...
Via NodePort
Section intitulée « Via NodePort »Pour mapper un port spécifique d’un nœud vers votre machine :
k3d cluster create demo -p "8082:30080@agent:0" --agents 2Créez un service de type NodePort avec le port 30080 :
apiVersion: v1kind: Servicemetadata: name: nginx-npspec: type: NodePort ports: - port: 80 nodePort: 30080 selector: app: nginxkubectl apply -f nodeport-svc.yamlcurl http://localhost:8082/Gérer les kubeconfigs
Section intitulée « Gérer les kubeconfigs »k3d gère automatiquement le kubeconfig. À la création d’un cluster, le
contexte est ajouté à votre fichier kubeconfig par défaut
(~/.kube/config) et le contexte courant bascule sur le nouveau cluster.
Récupérer le kubeconfig d’un cluster
Section intitulée « Récupérer le kubeconfig d’un cluster »k3d kubeconfig get demoÉcrire le kubeconfig dans un fichier séparé
Section intitulée « Écrire le kubeconfig dans un fichier séparé »k3d kubeconfig write demo/home/bob/.k3d/kubeconfig-demo.yamlFusionner dans le kubeconfig par défaut
Section intitulée « Fusionner dans le kubeconfig par défaut »k3d kubeconfig merge demo --kubeconfig-merge-defaultBasculer entre clusters k3d
Section intitulée « Basculer entre clusters k3d »kubectl config use-context k3d-demoCommandes essentielles
Section intitulée « Commandes essentielles »| Action | Commande |
|---|---|
| Créer un cluster | k3d cluster create <nom> |
| Créer depuis un fichier | k3d cluster create --config <fichier.yaml> |
| Lister les clusters | k3d cluster list |
| Arrêter un cluster | k3d cluster stop <nom> |
| Redémarrer un cluster | k3d cluster start <nom> |
| Supprimer un cluster | k3d cluster delete <nom> |
| Supprimer tous les clusters | k3d cluster delete --all |
| Lister les nœuds | k3d node list |
| Ajouter un agent | k3d node create <nom> --cluster <cluster> --role agent |
| Ajouter un server | k3d node create <nom> --cluster <cluster> --role server |
| Supprimer un nœud | k3d node delete <nom> |
| Importer une image | k3d image import <image> -c <cluster> |
| Créer un registre | k3d registry create <nom> --port <port> |
| Lister les registres | k3d registry list |
| Supprimer un registre | k3d registry delete <nom> |
| Récupérer le kubeconfig | k3d kubeconfig get <cluster> |
Dépannage
Section intitulée « Dépannage »Problèmes courants
Section intitulée « Problèmes courants »| Symptôme | Cause probable | Solution |
|---|---|---|
| Port déjà utilisé | Un autre service écoute sur ce port | Changez le port dans -p |
ErrImagePull avec image locale | imagePullPolicy absent | Ajoutez imagePullPolicy: Never |
| Cluster HA, nœud ne rejoint pas | Cluster créé sans --cluster-init | Recréez avec --servers 3 |
| Ingress ne répond pas | Port 80 non mappé au load balancer | Recréez avec -p "PORT:80@loadbalancer" |
registry.localhost introuvable | Résolution DNS locale manquante | Ajoutez dans /etc/hosts |
| Cluster ne redémarre pas | IPs des conteneurs changent | Utilisez --subnet auto |
k3d cluster start échoue | Volumes Docker corrompus | Supprimez et recréez le cluster |
Port déjà utilisé
Section intitulée « Port déjà utilisé »Symptôme : La création du cluster échoue avec “address already in use”.
Solution :
# Trouver le processus qui utilise le portsudo lsof -i :8888
# Utiliser un autre portk3d cluster create demo -p "9090:80@loadbalancer"Image locale non trouvée (ErrImagePull)
Section intitulée « Image locale non trouvée (ErrImagePull) »Symptôme : Votre Pod reste en ErrImagePull ou ImagePullBackOff.
Solution :
# Importer l'image dans le clusterk3d image import mon-app:v1 -c demo
# Vérifier le manifest : imagePullPolicy doit être Never ou IfNotPresentkubectl get pod <nom> -o jsonpath='{.spec.containers[0].imagePullPolicy}'Cluster HA qui ne converge pas
Section intitulée « Cluster HA qui ne converge pas »Symptôme : Un server reste en “NotReady” ou le cluster met très longtemps à démarrer.
Diagnostic :
# Vérifier les logs k3s d'un nœuddocker logs k3d-ha-demo-server-0 --tail 50
# Vérifier les ressources Dockerdocker stats --no-streamSolutions :
-
Assurez-vous d’avoir au moins 2 CPU et 4 Go de RAM disponibles
-
Si les IPs changent au restart, recréez avec
--subnet auto:Fenêtre de terminal k3d cluster delete ha-demok3d cluster create ha-demo --servers 3 --agents 2 --subnet auto
Registre local inaccessible
Section intitulée « Registre local inaccessible »Symptôme : docker push vers le registre échoue avec “connection refused”.
Diagnostic :
# Vérifier que le registre tournedocker ps --filter "name=registry"
# Tester la connexioncurl http://localhost:5111/v2/_catalogSolutions :
- Vérifiez que le port mappé est correct :
k3d registry list - Sur macOS/Windows, ajoutez le nom du registre dans
/etc/hosts
Réinitialiser complètement k3d
Section intitulée « Réinitialiser complètement k3d »Pour cette opération, supprimez tous les clusters et registres :
k3d cluster delete --allk3d registry delete --allPour supprimer aussi les volumes et réseaux Docker orphelins :
docker volume prune -fdocker network prune -fÀ retenir
Section intitulée « À retenir »- k3d exécute k3s dans des conteneurs Docker — le cluster Kubernetes local le plus rapide à créer (~20 secondes)
- Chaque nœud est un conteneur Docker : server (control-plane) ou agent (worker)
- Un load balancer Nginx (serverlb) est créé devant les servers
- Le mode multi-server (
--servers 3) active etcd distribué (HA) - Traefik est inclus nativement comme Ingress Controller
- metrics-server est également intégré (pas d’add-on à activer)
k3d image importcopie une image Docker locale dans le cluster--registry-createcrée un registre d’images local avec le cluster- Les fichiers de configuration YAML permettent des clusters reproductibles
- Le kubeconfig est fusionné automatiquement (préfixe
k3d-) - Utilisez
--subnet autopour éviter les problèmes d’IP au redémarrage