Aller au contenu

K3s ou Docker Compose : le bon choix pour un homelab

Cryptolab.re
Auteur
Cryptolab.re
Cryptolab est un blog personnel où je documente mes expérimentations techniques : infra, self-hosting, réseau, crypto et projets parfois inutiles, souvent instructifs.
Sommaire

J’ai longtemps gardé tout mon homelab sous Docker Compose. Pas par rejet de Kubernetes : Compose faisait le travail, les volumes étaient faciles à retrouver et je savais remettre un service en route sans relire une pile de manifests.

K3s est arrivé plus tard, quand j’ai voulu uniformiser les déploiements et préparer l’ajout d’autres machines. Je n’ai pas tout migré pour autant. Aujourd’hui, les deux cohabitent encore, et ce n’est pas une phase transitoire que je cherche absolument à supprimer.

Pour trancher, je regarde surtout la panne : avec lequel des deux vais-je retrouver les données et remettre le service en route sans improviser ?

En bref
#

  • Sur un serveur unique, Docker Compose reste mon choix par défaut.
  • K3s est bien une distribution Kubernetes. L’installation est légère, pas l’ensemble des sujets d’exploitation qui viennent avec.
  • Le minimum documenté pour un serveur K3s est de 2 cœurs et 2 Go de RAM, hors applications.
  • Le multi-nœuds n’apporte pas grand-chose aux services avec état tant que le stockage n’est pas réglé.
  • Trois serveurs K3s rendent le control-plane plus tolérant aux pannes. Ils ne rendent pas automatiquement les applications hautement disponibles.
  • Pour apprendre Kubernetes ou préparer une infra qui doit grandir, K3s est un très bon lab.

Compose ne devient pas mauvais au dixième conteneur
#

On lit parfois qu’il faudrait passer à Kubernetes dès que le nombre de conteneurs devient important. Je n’ai jamais trouvé ce seuil très utile.

Quarante conteneurs peuvent rester parfaitement lisibles si les stacks suivent les mêmes conventions. À l’inverse, six services suffisent pour créer du désordre si les volumes sont anonymes, les tags d’images flottants et les fichiers .env dispersés sur le serveur.

Sur une machine, Compose garde plusieurs avantages difficiles à battre :

  • un fichier décrit l’essentiel de l’application ;
  • les bind mounts indiquent clairement où vivent les données ;
  • le dépannage reste proche du système ;
  • la restauration ne dépend pas d’un control-plane ;
  • la consommation propre à l’outil est négligeable.

Pour faire un état des lieux, je commence généralement par ces commandes :

docker compose ls
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}"
docker volume ls
sudo ss -lntup

Si cette sortie est compréhensible, que les données sont localisées et que la restauration est documentée, passer à K3s ne va pas améliorer le service par magie.

Les limites de Compose existent quand même. Il pilote un moteur Docker, pas un parc de machines. Une politique restart: unless-stopped relance un conteneur sur son hôte, mais ne le déplace pas ailleurs si l’hôte tombe. À mesure que les stacks s’accumulent, les labels Traefik, les réseaux, les secrets et les tâches de sauvegarde finissent aussi par reposer sur des conventions maison.

On peut tenir longtemps avec ces conventions. Il faut simplement les écrire et les appliquer.

Ce que K3s m’a réellement apporté
#

K3s n’est pas un Compose amélioré. C’est Kubernetes, livré avec des choix raisonnables pour démarrer vite.

Une installation standard fournit notamment CoreDNS, Traefik, metrics-server, ServiceLB et le provisioner de stockage local-path. Flannel assure le réseau des pods par défaut. Le runtime est containerd, même si Docker est déjà installé sur la machine.

Ce que je cherchais surtout, c’était un modèle commun. Une application se décrit avec les mêmes objets que sur un autre cluster Kubernetes : Deployment, Service, Ingress, ConfigMap, Secret et PersistentVolumeClaim. Les namespaces et les labels remettent aussi un peu d’ordre après plusieurs années de Compose.

L’état désiré m’intéressait également. Si un pod disparaît, Kubernetes tente de le recréer. Sur plusieurs agents, un workload sans état peut être replacé sur un autre nœud. Pour des frontends, des workers ou de petits services sans données locales, le comportement est utile et assez prévisible.

K3s reste surtout un bon terrain d’apprentissage. kubectl, les probes, les RBAC, Helm et le scheduler ne sont pas des versions simplifiées propres à K3s. Quand le homelab sert aussi de laboratoire pour le travail, cet argument suffit souvent à justifier l’installation.

Helm mérite tout de même une réserve. Un chart évite d’écrire certains manifests, mais il ajoute une dépendance au mainteneur du chart et à ses choix de valeurs. Je préfère un déploiement simple que je comprends à un chart très complet que je n’ose plus mettre à jour.

Ce que K3s ajoute à l’exploitation
#

L’installation de K3s tient en peu de commandes. Ce n’est pas la partie qui coûte du temps.

Il faut ensuite gérer l’accès à l’API, le kubeconfig, les mises à niveau, les événements Kubernetes, le réseau des pods, les volumes persistants et la sauvegarde du datastore. Les pannes changent aussi de forme : un pod peut être sain alors que son Service ne cible aucun endpoint, ou rester en Pending parce qu’un PVC ne peut plus être monté.

Les commandes de base deviennent celles-ci :

kubectl get nodes -o wide
kubectl get pods -A -o wide
kubectl get svc -A -o wide
kubectl get ingress -A
kubectl get pvc -A
kubectl get events -A --sort-by=.lastTimestamp

Rien d’anormal pour Kubernetes, mais ce temps d’exploitation doit entrer dans le choix initial.

Le réseau demande également un minimum de préparation. L’API K3s écoute sur TCP 6443. Avec Flannel en mode VXLAN, les nœuds communiquent sur UDP 8472. Ce dernier port doit rester limité au réseau du cluster et ne doit pas être publié sur Internet.

Autre détail facile à rater : Traefik utilise un service LoadBalancer pris en charge par ServiceLB. Par défaut, les ports 80 et 443 sont occupés sur les nœuds éligibles. Si un Traefik ou un Nginx tourne déjà sous Docker, il faut décider lequel garde ces ports avant d’installer K3s.

Les secrets demandent la même prudence. Un objet Kubernetes Secret encode les valeurs, il ne constitue pas un coffre-fort. K3s sait activer le chiffrement au repos avec --secrets-encryption, mais ce n’est pas le réglage par défaut. Le kubeconfig et le token serveur doivent eux aussi être traités comme des secrets d’administration.

Le stockage reste le point difficile
#

C’est la partie qui m’empêcherait de conseiller une migration rapide.

Le provisioner local-path de K3s crée un volume sur le disque d’un nœud. Sur un cluster à une seule machine, le comportement est simple. Avec plusieurs nœuds, le nom PersistentVolume peut donner une impression trompeuse : le volume persiste, mais il ne devient pas distribué.

Si le nœud qui possède les données tombe, Kubernetes peut recréer le pod ailleurs. Le nouveau pod n’aura pas pour autant accès au disque de l’ancien nœud. Pour une application sans état, aucun problème. Pour PostgreSQL, Immich ou Nextcloud, le service reste indisponible.

Le stockage doit donc être choisi avant de migrer les applications avec état :

  • un partage réseau existant et un pilote adapté ;
  • un système distribué comme Longhorn ;
  • une réplication assurée par l’application ;
  • un placement fixe sur un nœud, en acceptant l’absence de bascule ;
  • ou une restauration depuis les sauvegardes en cas de perte.

J’utilise Longhorn pour préparer la suite, mais avec un seul nœud il ne fournit aucune haute disponibilité matérielle. Sa documentation de production pour le moteur V1 recommande au minimum trois nœuds, quatre vCPU et 4 Gio de RAM par nœud. Cela donne une meilleure idée du coût réel qu’un simple tableau des besoins K3s.

Il ne faut pas non plus confondre replicas et sauvegardes. Une suppression de fichier ou une corruption applicative sera très bien répliquée sur les autres disques. Je garde donc une copie hors cluster et un test de restauration séparé.

Trois nœuds ne suffisent pas à faire de la HA
#

Sur un serveur unique, K3s utilise SQLite par défaut. Pour rendre le control-plane tolérant à la panne d’un serveur avec etcd embarqué, il faut au moins trois serveurs. Le nombre doit rester impair pour conserver un quorum cohérent.

Cette topologie protège l’API et le datastore contre certaines pannes, pas les applications elles-mêmes.

Pour qu’un service continue réellement à répondre après la perte d’une machine, il faut aussi :

  • plusieurs replicas applicatifs répartis sur différents nœuds ;
  • un stockage encore accessible ;
  • un chemin réseau fonctionnel vers l’Ingress ;
  • une adresse stable pour joindre le cluster ;
  • aucune dépendance critique restée sur le nœud perdu.

Un cluster de trois mini-PC adossé à un seul NAS et à un seul switch garde deux points uniques de panne. Ce compromis peut être parfaitement acceptable à la maison. Je préfère seulement parler de tolérance à la panne d’un nœud plutôt que de haute disponibilité globale.

La sauvegarde du cluster doit aussi couvrir le datastore K3s et /var/lib/rancher/k3s/server/token. Ce fichier n’est pas accessoire : K3s l’utilise pour chiffrer des données confidentielles stockées dans le datastore. Restaurer un snapshot avec un autre token ne fonctionne pas.

Mon choix aujourd’hui
#

Mon installation reste volontairement hybride :

  • un nœud K3s, avec la possibilité d’ajouter des agents plus tard ;
  • Traefik fourni par K3s pour les Ingress ;
  • Longhorn pour le stockage persistant, sans prétention de HA à ce stade ;
  • Helm lorsque le chart est maintenu et reste lisible ;
  • Docker Compose pour quelques tests et services temporaires.

Je ne migre un service que si le déplacement règle quelque chose : déploiement plus cohérent, besoin de primitives Kubernetes ou préparation du multi-nœuds. Un service isolé avec un volume et deux variables peut très bien rester sous Compose.

Si je repartais aujourd’hui avec une seule machine et sans objectif d’apprentissage Kubernetes, je choisirais encore Compose. Je passerais du temps sur l’arborescence, les versions d’images, les sauvegardes et la supervision avant de toucher à un orchestrateur.

Avec plusieurs machines et l’envie réelle d’exploiter Kubernetes, je choisirais K3s. Mais je déciderais du stockage et de la procédure de restauration avant de déployer la première base de données.

Migrer sans tout déplacer d’un coup
#

La cohabitation évite une bascule risquée. Voici l’ordre qui m’a paru le plus sain :

  1. Inventorier les ports, volumes, secrets et tâches planifiées côté Compose.
  2. Restaurer un service depuis les sauvegardes, avant toute migration.
  3. Installer K3s en tenant compte des ports 80 et 443 déjà utilisés.
  4. Commencer par une application sans état.
  5. Mettre en place la sauvegarde du datastore K3s et du token serveur.
  6. Tester une mise à niveau avant de déplacer un service important.
  7. Migrer les applications avec état seulement après validation du stockage.

Docker et K3s peuvent tourner sur le même hôte. Il faut toutefois garder en tête que leurs runtimes et leurs volumes sont distincts. Une image déjà présente dans Docker n’est pas automatiquement disponible dans containerd, et un volume Docker n’est pas un PVC Kubernetes.

Conclusion
#

Sur une seule machine, je resterais sous Docker Compose. Le dépannage est direct et la restauration demande moins de pièces.

Je choisirais K3s pour apprendre Kubernetes, uniformiser plusieurs déploiements ou exploiter réellement plusieurs nœuds. Pas pour remplacer un fichier Compose qui ne pose aucun problème.

Dans les deux cas, je garde la même limite : aucun service avec état ne bouge tant que sa sauvegarde et sa restauration n’ont pas été testées.

Sources
#

Articles connexes

Docker Compose : arrêtez de mettre latest dans vos fichiers

Le tag latest est confortable. On écrit un compose.yml, on lance docker compose up -d, et le service démarre. Pas besoin de choisir une version de PostgreSQL, Redis, Traefik, Gitea, Vaultwarden ou n’importe quelle application auto-hébergée. Le problème, c’est que latest ne veut pas dire “dernière version stable adaptée à mon environnement”. Ça veut seulement dire : “ce tag pointe vers quelque chose dans le registre au moment où Docker le résout”. Ce quelque chose peut changer sans que votre fichier Compose change. Pour une stack de test, ce n’est pas très grave. Pour une base de données, un reverse proxy exposé, un service d’authentification ou une application avec des volumes persistants, c’est une mauvaise convention d’exploitation. Le vrai sujet n’est pas Docker. C’est la reproductibilité.

opencode + Firecrawl : remplacer SearXNG pour l'IA locale

Dans mon setup opencode + Ollama sur RTX 3090, j’avais commencé avec SearXNG comme source web via MCP. Ça fonctionnait, mais ce n’était pas exactement le bon outil pour mon usage. SearXNG est un métamoteur de recherche. Il trouve des pages. Firecrawl est plus proche d’une brique d’extraction : il cherche, scrape, nettoie, crawl et renvoie du contenu exploitable par un agent. Pour un assistant local qui doit lire de la documentation, vérifier une API récente ou comparer plusieurs sources techniques, la différence se sent assez vite.

Assistant IA local : Ollama + opencode sur RTX 3090

J’utilise des LLMs comme assistants de code depuis début 2026. D’abord avec des API cloud, puis en local. Ce qui a changé avec une RTX 3090, c’est la bascule vers un modèle de travail où la latence et la confidentialité deviennent moins pénalisantes. L’inférence locale devient crédible pour du code à partir de 24 Go VRAM. Voici mon setup, les chiffres réels et ce qui tient vraiment la route.