Installation cluster K3s sur Raspberry Pi

Le projet prend forme

Tout a commencé simplement : un ami m'a offert une Raspberry Pi 4 2GB pour que je m'entraîne et acquière des compétences en infrastructure. Puis un autre ami m'a donné une Raspberry Pi 3+ 1GB pour que je découvre Home Assistant. J'ai également réussi à récupérer une Raspberry Pi 3 1GB qui traînait.

Au fur et à mesure que mes idées prenaient forme, je me suis rendu compte que ce que je voulais faire demandait un peu plus de ressources. J'ai donc investi dans une Raspberry Pi 4 8GB, et pour faire les choses proprement, j'ai acheté :

  • Un dock d'alimentation (~25€) pour éviter de gaspiller des prises électriques
  • Un rack à Raspberry Pi (~15€) pour organiser tout ce petit monde

Budget total investi : ~160€ (sans compter les Pi offertes/récupérées)

L'architecture finale

Mon cluster K3s se compose de 4 nœuds :

Node Master (Control Plane)

  • rpi4-master - 192.168.1.51
  • Raspberry Pi 4 8GB
  • Rôles : control-plane, master
  • Héberge l'API server, le scheduler, et etcd

Nodes Workers

  • rpi4-worker - 192.168.1.50 (Raspberry Pi 4 2GB)
  • rpi3-worker1 - 192.168.1.36 (Raspberry Pi 3+ 1GB)
  • rpi3-worker2 - 192.168.1.15 (Raspberry Pi 3 1GB)

Tous les nœuds tournent sous Raspberry Pi OS (basé sur Debian 13 trixie) avec le kernel 6.12.47+rpt-rpi-v8 et K3s v1.28.5+k3s1.

Mon NAS QNAP (192.168.1.18) est également intégré au cluster pour fournir du stockage persistant via NFS.

Pourquoi K3s ?

K3s est une distribution Kubernetes légère parfaitement adaptée aux environnements edge, IoT, et homelab. Quelques avantages :

  • Léger : Binary de ~100MB vs plusieurs GB pour Kubernetes vanilla
  • Simple : Installation en une commande
  • Complet : Inclut un load balancer (Traefik), un stockage local, et tout le nécessaire
  • Faible empreinte mémoire : Idéal pour les Raspberry Pi avec 1-2GB de RAM

Concepts clés Kubernetes/K3s

Pour comprendre comment fonctionne le cluster, voici les concepts essentiels :

Control Plane (nœud master) :

  • API Server : Point d'entrée unique pour toutes les commandes kubectl
  • Scheduler : Décide sur quel nœud placer les nouveaux Pods en fonction des ressources disponibles
  • etcd : Base de données clé-valeur qui stocke l'état du cluster (où sont les Pods, quelle configuration, etc.)
  • Controller Manager : Surveille l'état du cluster et agit pour atteindre l'état désiré

Worker Nodes :

  • Kubelet : Agent qui s'assure que les conteneurs tournent correctement
  • Container Runtime : containerd dans notre cas, qui exécute les conteneurs
  • Kube-proxy : Gère le réseau et les règles iptables

Ressources Kubernetes :

  • Pod : Plus petite unité déployable, contient un ou plusieurs conteneurs
  • Service : IP fixe pour accéder à un groupe de Pods (car les Pods peuvent être supprimés/recréés)
  • Ingress : Règles de routage HTTP/HTTPS pour exposer les services à l'extérieur
  • PersistentVolume (PV) : Stockage qui persiste même si le Pod est supprimé
  • PersistentVolumeClaim (PVC) : Demande de stockage par une application

Préparation du réseau

Attribution d'IPs fixes

Pour un cluster stable, il est crucial d'avoir des IPs fixes pour chaque nœud. Pourquoi ?

  • Le nœud master doit toujours être accessible à la même adresse (192.168.1.51:6443)
  • Les workers doivent pouvoir rejoindre le master de manière fiable
  • Facilite le debug et le monitoring

J'ai configuré mon routeur pour réserver :

  • 192.168.1.51 pour rpi4-master
  • 192.168.1.50 pour rpi4-worker
  • 192.168.1.36 pour rpi3-worker1
  • 192.168.1.15 pour rpi3-worker2

Configuration réseau sur chaque Pi

Sur chaque Raspberry Pi, j'ai configuré /etc/network/interfaces :

auto eth0
iface eth0 inet static
    address 192.168.1.51/24  # Adapter l'IP pour chaque nœud
    gateway 192.168.1.1
    dns-nameservers 192.168.1.1 8.8.8.8

Puis désactivé dhcpcd pour éviter les conflits :

sudo systemctl disable dhcpcd
sudo systemctl stop dhcpcd
sudo systemctl enable networking
sudo reboot

Préparation système

Avant d'installer K3s, quelques configurations système sont nécessaires :

1. Désactiver le swap

Kubernetes ne fonctionne pas correctement avec le swap activé. Pourquoi ?

  • Le swap interfère avec la gestion mémoire des Pods
  • Kubernetes veut contrôler précisément combien de RAM chaque Pod utilise
  • Le swap ralentit les performances de manière imprévisible
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo systemctl disable dphys-swapfile

2. Activer les cgroups

Les cgroups (control groups) sont essentiels pour Kubernetes car ils permettent :

  • D'isoler les ressources (CPU, RAM) de chaque conteneur
  • De limiter l'utilisation des ressources par Pod
  • D'éviter qu'un conteneur monopolise toutes les ressources du nœud

Éditer /boot/firmware/cmdline.txt et ajouter à la fin de la ligne (sans retour à la ligne) :

cgroup_memory=1 cgroup_enable=memory

Puis redémarrer :

sudo reboot

3. Installer les dépendances

sudo apt update
sudo apt install -y curl iptables

Installation du nœud master

Sur rpi4-master (192.168.1.51), j'ai installé K3s en mode server :

curl -sfL https://get.k3s.io | sh -s - server \
  --disable traefik \
  --write-kubeconfig-mode 644 \
  --node-ip 192.168.1.51 \
  --advertise-address 192.168.1.51

Explications des options :

  • --disable traefik : Je désactive Traefik car j'utilise nginx-ingress-controller
  • --write-kubeconfig-mode 644 : Permet de lire le kubeconfig sans sudo
  • --node-ip : Force l'IP du nœud (important avec des IPs fixes)
  • --advertise-address : IP sur laquelle l'API server écoute (les workers se connecteront ici)

Récupération du token

Pour que les workers puissent rejoindre le cluster, il faut récupérer le token :

sudo cat /var/lib/rancher/k3s/server/node-token

Exemple de token :

K10abc123def456ghi789jkl012mno345pqr678stu901vwx234yz::server:abcdef1234567890

Vérification

kubectl get nodes

Résultat :

NAME          STATUS   ROLES                  AGE   VERSION
rpi4-master   Ready    control-plane,master   2m    v1.28.5+k3s1

Installation des workers

Sur chaque worker (rpi4-worker, rpi3-worker1, rpi3-worker2), j'ai exécuté :

curl -sfL https://get.k3s.io | K3S_URL=https://192.168.1.51:6443 \
  K3S_TOKEN="<TOKEN_RÉCUPÉRÉ>" sh -s - agent \
  --node-ip <IP_DU_WORKER>

Par exemple, sur rpi4-worker (192.168.1.50) :

curl -sfL https://get.k3s.io | K3S_URL=https://192.168.1.51:6443 \
  K3S_TOKEN="K10abc123def456ghi789jkl012mno345pqr678stu901vwx234yz::server:abcdef1234567890" sh -s - agent \
  --node-ip 192.168.1.50

Vérification finale du cluster

De retour sur le master :

kubectl get nodes -o wide

Résultat :

NAME           STATUS   ROLES                  AGE   VERSION        INTERNAL-IP     OS-IMAGE
rpi4-master    Ready    control-plane,master   10m   v1.28.5+k3s1   192.168.1.51    Raspberry Pi OS
rpi4-worker    Ready    <none>                 5m    v1.28.5+k3s1   192.168.1.50    Raspberry Pi OS
rpi3-worker1   Ready    <none>                 4m    v1.28.5+k3s1   192.168.1.36    Raspberry Pi OS
rpi3-worker2   Ready    <none>                 3m    v1.28.5+k3s1   192.168.1.15    Raspberry Pi OS

Le cluster est opérationnel ! 🎉

Premiers pas

Configuration kubectl en local

Pour gérer le cluster depuis mon PC, j'ai copié le kubeconfig :

# Sur le master
sudo cat /etc/rancher/k3s/k3s.yaml

Puis sur mon PC, j'ai créé ~/.kube/config en remplaçant 127.0.0.1 par 192.168.1.51.

Test avec un Pod simple

kubectl run nginx-test --image=nginx --port=80
kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
nginx-test   1/1     Running   0          10s

Nettoyage

kubectl delete pod nginx-test

Points d'attention

Limitations matérielles

Les Raspberry Pi 3 avec 1GB de RAM ont des limitations :

  • Éviter de programmer des Pods gourmands sur ces nœuds
  • Utiliser des nodeSelector ou nodeAffinity pour cibler les nœuds appropriés
  • Monitorer l'utilisation mémoire régulièrement

Surveillance du cluster

# Utilisation CPU/Mémoire des nœuds
kubectl top nodes

# Utilisation des Pods
kubectl top pods -A

Gestion de l'alimentation

Le dock d'alimentation est essentiel :

  • Assure une alimentation stable pour tous les Pi
  • Évite les sous-tensions qui causent des redémarrages
  • Réduit l'encombrement des prises

La suite

Maintenant que le cluster est en place, voici les prochaines étapes pour construire ce homelab :

  1. Migration du site web vers Docker et K3s

    • Dockerisation du site statique Flask
    • Premier déploiement dans K3s
  2. Exposition des services du NAS QNAP

    • Redirection des services externes (Plex, Passbolt, Fonas, arr-stack)
    • Configuration des Endpoints manuels dans K3s
  3. Accès distant avec Tailscale

    • Installation sur les 4 Raspberry Pi et le PC
    • Gestion du cluster depuis n'importe où avec kubectl
  4. Découverte de Helm

    • Premiers pas avec les Helm charts
    • Templating et gestion des applications
  5. Infrastructure as Code

    • nginx-ingress-controller, cert-manager, NFS provisioner
    • GitOps avec ArgoCD
    • Gestion sécurisée des secrets avec Sealed Secrets

Le cluster K3s est la fondation de tout le homelab. Avec ces 4 Raspberry Pi et un investissement de ~160€, je dispose maintenant d'une infrastructure Kubernetes complète, prête à héberger tous mes projets !