Ajout d'une nouvelle raspberry dans le cluster k3s
Introduction
Mon cluster K3s tournait jusqu'ici avec 4 Raspberry Pi, mais j'avais besoin de plus de ressources pour héberger Home Assistant et les futures applications. J'ai donc décidé d'ajouter un 5ème nœud: une Raspberry Pi 4 Model B 4GB équipée d'un SSD externe pour améliorer les performances I/O et la durabilité par rapport aux cartes SD.
Matériel utilisé
- Raspberry Pi 4 Model B 4GB RAM
- SSD externe USB 3.0 (240 Go)
- Alimentation USB-C 5V 3A
- Câble Ethernet
État initial du cluster
Avant l'ajout:
- rpi4-master: 8GB RAM (control-plane)
- rpi4-worker: 2GB RAM (worker)
- rpi3-worker1: 1GB RAM (worker)
- rpi3-worker2: 1GB RAM (worker)
Total: 4 nœuds, ~12 GB RAM
Objectif
Ajouter rpi4-worker2 au cluster avec:
- Boot et rootfs sur SSD pour de meilleures performances
- Configuration automatisée via Ansible
- Aucune intervention manuelle après l'installation initiale
Étape 1: Installation système sur SSD
Préparation avec Raspberry Pi Imager
J'ai utilisé Raspberry Pi Imager pour installer Debian 13 (Trixie) directement sur le SSD.
Configuration dans Pi Imager:
- OS: Debian GNU/Linux 13 (Trixie) 64-bit
- Stockage: SSD externe USB
- Paramètres personnalisés:
- Hostname:
rpi4-worker2 - Activer SSH avec authentification par mot de passe
- Utilisateur:
piavec mot de passe - Locale:
fr_FR.UTF-8 - Timezone:
Europe/Paris - Clavier: French
- Hostname:
Boot USB sur Raspberry Pi 4
Les Raspberry Pi 4 récentes supportent le boot USB natif. J'ai vérifié que le bootloader était à jour:
# Après premier boot sur la RPi4
sudo rpi-eeprom-update
# Si mise à jour nécessaire:
sudo rpi-eeprom-update -a
sudo reboot
Une fois le bootloader à jour, la RPi4 boote directement depuis le SSD sans carte SD.
Étape 2: Configuration de l'inventaire Ansible
J'ai ajouté le nouveau nœud dans mon inventaire Ansible.
Fichier inventory/hosts.ini
[masters]
rpi4-master ansible_host=rpi4-master
[workers]
rpi3-worker1 ansible_host=rpi3-worker1
rpi3-worker2 ansible_host=rpi3-worker2
rpi4-worker ansible_host=rpi4-worker
rpi4-worker2 ansible_host=rpi4-worker2 # Nouveau nœud
[k3s:children]
masters
workers
[k3s:vars]
ansible_user=pi
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
Test de connectivité
ansible rpi4-worker2 -i inventory/hosts.ini -m ping
Résultat:
rpi4-worker2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
Étape 3: Configuration système avec Ansible
J'ai utilisé le playbook 03-system-config.yml qui configure automatiquement le système pour K3s.
Lancement du playbook
ansible-playbook -i inventory/hosts.ini playbooks/03-system-config.yml --limit rpi4-worker2
Ce que fait ce playbook
1. Installation des packages essentiels
- name: Installer les packages essentiels
apt:
name:
- curl
- wget
- git
- vim
- htop
- net-tools
- iptables
- ca-certificates
- gnupg
- lsb-release
state: present
update_cache: yes
2. Désactivation du swap (requis pour K3s)
Kubernetes (et donc K3s) requiert que le swap soit complètement désactivé.
- name: Désactiver le swap immédiatement
command: swapoff -a
- name: Supprimer le fichier swap s'il existe
file:
path: /swapfile
state: absent
- name: Désactiver le swap au boot (dans fstab)
lineinfile:
path: /etc/fstab
regexp: '.*swap.*'
state: absent
3. Configuration des cgroups
Les cgroups sont nécessaires pour que K3s puisse limiter les ressources des conteneurs.
- name: Vérifier la présence de cgroups dans cmdline.txt
shell: grep -q "cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory" /boot/firmware/cmdline.txt
register: cgroup_check
failed_when: false
- name: Créer un backup de cmdline.txt avant modification
copy:
src: /boot/firmware/cmdline.txt
dest: /boot/firmware/cmdline.txt.backup
remote_src: yes
when: cgroup_check.rc != 0
- name: Ajouter cgroups à cmdline.txt si absent
lineinfile:
path: /boot/firmware/cmdline.txt
backrefs: yes
regexp: '^(.*?)(\s*$)'
line: '\1 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory\2'
backup: no
when: cgroup_check.rc != 0
Note importante: Le backup automatique d'Ansible (backup: yes) ne fonctionne pas sur /boot/firmware car c'est un système de fichiers FAT32 qui n'accepte pas les caractères : dans les noms de fichiers (le timestamp du backup contient des :). J'ai donc créé un backup manuel avec un nom simple.
4. Augmentation des limites système
- name: Configurer les limites système
blockinfile:
path: /etc/security/limits.conf
block: |
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
Cela permet d'augmenter le nombre maximum de fichiers et processus ouverts, nécessaire pour K3s.
5. Chargement des modules kernel
- name: Charger les modules kernel nécessaires
modprobe:
name: "{{ item }}"
state: present
loop:
- overlay
- br_netfilter
- name: Rendre les modules kernel persistants
copy:
content: |
overlay
br_netfilter
dest: /etc/modules-load.d/k3s.conf
- overlay: Permet d'utiliser OverlayFS pour les conteneurs
- br_netfilter: Permet au traffic des bridges de passer par iptables
6. Configuration sysctl
- name: Activer le forward IPv4
sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
reload: yes
sysctl_file: /etc/sysctl.d/k3s.conf
- name: Configurer bridge netfilter
sysctl:
name: "{{ item }}"
value: '1'
state: present
reload: yes
sysctl_file: /etc/sysctl.d/k3s.conf
loop:
- net.bridge.bridge-nf-call-iptables
- net.bridge.bridge-nf-call-ip6tables
Ces paramètres permettent:
- Le forwarding IPv4 (routage de paquets)
- Le passage du traffic des bridges par iptables
Redémarrage nécessaire
Si les cgroups ont été modifiés, un redémarrage est nécessaire pour les activer:
ansible rpi4-worker2 -i inventory/hosts.ini -m reboot --become
Étape 4: Installation de K3s
Une fois le système configuré, j'ai lancé le playbook d'installation K3s.
Lancement du playbook
ansible-playbook -i inventory/hosts.ini playbooks/04-install-k3s.yml --limit rpi4-worker2,rpi4-master
Note: On inclut le master pour récupérer le token d'authentification.
Ce que fait ce playbook
1. Sur le master: récupération du token
- name: Récupérer le token K3s
slurp:
src: /var/lib/rancher/k3s/server/node-token
register: k3s_token_raw
- name: Stocker le token K3s
set_fact:
k3s_token: "{{ k3s_token_raw['content'] | b64decode | trim }}"
Le token est nécessaire pour authentifier les workers auprès du master.
2. Sur le worker: installation de K3s agent
- name: Vérifier si K3s agent est déjà installé
stat:
path: /usr/local/bin/k3s-agent-uninstall.sh
register: k3s_agent_installed
- name: Télécharger le script d'installation K3s
shell: curl -sfL https://get.k3s.io -o /tmp/k3s-install.sh && chmod +x /tmp/k3s-install.sh
when: not k3s_agent_installed.stat.exists
- name: Installer K3s agent sur les workers
shell: |
INSTALL_K3S_VERSION=v1.28.5+k3s1 \
K3S_URL=https://100.121.116.90:6443 \
K3S_TOKEN={{ k3s_token }} \
INSTALL_K3S_EXEC="agent --node-name {{ ansible_hostname }}" \
/tmp/k3s-install.sh
when: not k3s_agent_installed.stat.exists
Variables importantes:
INSTALL_K3S_VERSION=v1.28.5+k3s1: Version stable de K3sK3S_URL=https://100.121.116.90:6443: URL du master (IP Tailscale pour supporter workers distants)K3S_TOKEN: Token d'authentification récupéré du masterINSTALL_K3S_EXEC="agent --node-name rpi4-worker2": Mode agent avec nom du nœud
3. Vérification que le nœud a rejoint le cluster
- name: Attendre que tous les workers rejoignent le cluster
shell: kubectl get nodes --no-headers | wc -l
register: node_count
until: node_count.stdout | int == 5
retries: 12
delay: 10
Le playbook attend jusqu'à 2 minutes que les 5 nœuds soient présents.
Problèmes rencontrés et solutions
Problème 1: Erreur de backup sur FAT32
Symptôme:
fatal: [rpi4-worker2]: FAILED! => {
"msg": "Could not make backup of /boot/firmware/cmdline.txt to
/boot/firmware/cmdline.txt.3790.2025-12-31@19:59:05~:
[Errno 22] Invalid argument"
}
Cause: Le système de fichiers /boot/firmware est en FAT32 qui n'accepte pas les caractères : dans les noms de fichiers. Le nom de backup automatique d'Ansible contient un timestamp avec des :.
Solution: Désactiver le backup automatique (backup: no) et créer manuellement un backup avec un nom simple (cmdline.txt.backup).
Problème 2: Node password rejected
Symptôme:
Node password rejected, duplicate hostname or contents of
'/etc/rancher/node/password' may not match server node-passwd entry
Cause: Un secret Kubernetes existe déjà pour ce hostname, probablement d'une installation précédente ou d'une tentative échouée.
Solution:
# Sur le master: supprimer le secret
kubectl delete secret rpi4-worker2.node-password.k3s -n kube-system
# Sur le worker: nettoyer et redémarrer
sudo systemctl stop k3s-agent
sudo rm -rf /etc/rancher/node
sudo systemctl start k3s-agent
Problème 3: Espace disque insuffisant (sur rpi4-master)
Durant les tests, j'ai découvert un fichier swap de 2.1 Go sur rpi4-master qui n'aurait pas dû exister.
Solution:
# Désactiver et supprimer le swap
sudo swapoff -a
sudo rm -f /var/swap
# Nettoyer les journaux
sudo journalctl --vacuum-time=7d
Résultat: passage de 77% à 69% d'utilisation disque, récupération de 2.1 Go.
Vérification du cluster
État final
kubectl get nodes -o wide
Résultat:
NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE
rpi4-master Ready control-plane,master 21d v1.28.5+k3s1 192.168.1.51 Debian GNU/Linux 13 (trixie)
rpi4-worker Ready <none> 21d v1.28.5+k3s1 192.168.1.50 Debian GNU/Linux 13 (trixie)
rpi3-worker1 Ready <none> 21d v1.28.5+k3s1 192.168.1.36 Debian GNU/Linux 13 (trixie)
rpi3-worker2 Ready <none> 21d v1.28.5+k3s1 192.168.1.15 Debian GNU/Linux 13 (trixie)
rpi4-worker2 Ready <none> 26m v1.28.5+k3s1 192.168.1.33 Debian GNU/Linux 13 (trixie)
Ressources du cluster
kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
rpi4-master 245m 3% 2841Mi 36%
rpi4-worker 156m 7% 892Mi 46%
rpi3-worker1 89m 8% 512Mi 53%
rpi3-worker2 76m 7% 489Mi 50%
rpi4-worker2 112m 2% 736Mi 18% ← Beaucoup de RAM disponible
Capacité totale du cluster:
- CPU: ~12 cores
- RAM: ~16 GB (8 + 2 + 4 + 1 + 1)
- Nœuds: 5 (1 master + 4 workers)
Performances SSD vs SD Card
Benchmarks d'écriture séquentielle
# Sur rpi4-worker2 (SSD)
dd if=/dev/zero of=/tmp/test bs=1M count=1000 oflag=direct
1000+0 records in
1000+0 records out
1048576000 bytes copied, 4.2 s, 250 MB/s
# Sur rpi3-worker1 (SD card)
dd if=/dev/zero of=/tmp/test bs=1M count=1000 oflag=direct
1000+0 records in
1000+0 records out
1048576000 bytes copied, 28.5 s, 36.8 MB/s
Résultat: Le SSD est 6.8x plus rapide en écriture séquentielle.
Benchmarks de latence (random I/O)
# Sur rpi4-worker2 (SSD)
sudo ioping -c 10 /
10 requests completed in 7.2 ms, 1.39 k iops
# Sur rpi3-worker1 (SD card)
sudo ioping -c 10 /
10 requests completed in 132.8 ms, 75.3 iops
Résultat: Le SSD a une latence 18x meilleure pour les I/O aléatoires.
Impact sur Kubernetes
Ces performances se traduisent par:
- ✅ Démarrage des pods plus rapide: Les images se chargent plus vite
- ✅ Meilleure stabilité: Moins de timeouts lors des opérations I/O intensives
- ✅ Durabilité: Les SSD résistent bien mieux aux écritures fréquentes
- ✅ Bases de données: Idéal pour les applications avec beaucoup d'écritures (Home Assistant, bases de données)
Récapitulatif des commandes
Ordre d'exécution pour ajouter un nouveau nœud:
# 1. Ajouter le nœud dans inventory/hosts.ini
vim inventory/hosts.ini
# 2. Tester la connectivité
ansible rpi4-worker2 -i inventory/hosts.ini -m ping
# 3. Configurer le système
ansible-playbook -i inventory/hosts.ini playbooks/03-system-config.yml --limit rpi4-worker2
# 4. Redémarrer si nécessaire (cgroups modifiés)
ansible rpi4-worker2 -i inventory/hosts.ini -m reboot --become
# 5. Installer K3s
ansible-playbook -i inventory/hosts.ini playbooks/04-install-k3s.yml --limit rpi4-worker2,rpi4-master
# 6. Vérifier le cluster
kubectl get nodes
Avantages du SSD
| Aspect | SD Card | SSD | Amélioration |
|---|---|---|---|
| Lecture séquentielle | ~90 MB/s | ~400 MB/s | 4.4x |
| Écriture séquentielle | ~37 MB/s | ~250 MB/s | 6.8x |
| Latence (IOPS) | ~75 iops | ~1390 iops | 18x |
| Durabilité (cycles) | ~3000 | ~100000 | 33x |
| Prix (240 Go) | ~15€ | ~30€ | 2x |
Verdict: Le surcoût du SSD est largement justifié pour les nœuds qui hébergent des applications avec beaucoup d'I/O.
Inconvénients du SSD
❌ Coût: 2x plus cher qu'une carte SD
❌ Encombrement: Câble USB supplémentaire
❌ Consommation: Légèrement plus élevée (~0.5W de plus)
❌ Boot: Nécessite un bootloader à jour (simple sur RPi4)
Conclusion
L'ajout de rpi4-worker2 avec SSD a été un succès. Grâce à Ansible, tout le processus est automatisé et reproductible:
- ✅ Configuration système en une commande
- ✅ Installation K3s en une commande
- ✅ Nœud opérationnel en moins de 10 minutes
Le cluster dispose maintenant de 5 nœuds et 16 GB RAM, avec des performances I/O excellentes sur le nœud principal destiné aux applications critiques.
Prochaines étapes
- ✅ Cluster à 5 nœuds opérationnel
- ✅ Home Assistant déployé sur rpi4-worker2
- ⏳ Migration de Passbolt depuis le NAS
- ⏳ Migration de la *arr stack
- ⏳ Mise en place du monitoring (Prometheus + Grafana)
Ressources: