
Mélanger des Raspberry Pi (ARM) et des machines x86 dans un même cluster k3s fonctionne nativement : l'agent détecte son architecture, et le bon label se pose tout seul. Le réflexe moderne n'est pas de forcer chaque pod sur une architecture, mais d'utiliser des images multi-architecture que Kubernetes tire automatiquement selon le nœud. Ce guide montre comment ajouter un nœud ARM, exploiter les images multi-arch, et cibler une architecture avec nodeSelector ou nodeAffinity quand c'est nécessaire. Pour utilisateurs Kubernetes intermédiaires. Commandes validées sur k3d (k3s 1.31).
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ajouter un nœud ARM à un cluster k3s
- Comprendre le tirage automatique des images multi-architecture
- Cibler une architecture avec
nodeSelectoretnodeAffinity - Isoler des nœuds avec taints et tolerations
Prérequis
Section intitulée « Prérequis »- Un cluster k3s existant (voir installer k3s)
- Une ou plusieurs machines ARM (Raspberry Pi en OS 64 bits pour viser
arm64)
Ajouter un nœud ARM au cluster
Section intitulée « Ajouter un nœud ARM au cluster »k3s est disponible pour x86_64 (AMD64), arm64/aarch64 et armhf (ARM 32 bits). L'agent télécharge le binaire correspondant à sa plateforme : il n'y a aucun paramètre d'architecture à passer.
Récupérez d'abord le token sur le nœud serveur :
sudo cat /var/lib/rancher/k3s/server/node-tokenPuis, sur le Raspberry Pi, lancez l'agent en pointant vers le serveur :
curl -sfL https://get.k3s.io | \ K3S_URL=https://<ip-serveur>:6443 \ K3S_TOKEN=<token> sh -Vérifier l'architecture des nœuds
Section intitulée « Vérifier l'architecture des nœuds »Le kubelet pose automatiquement les labels bien connus kubernetes.io/arch et kubernetes.io/os sur chaque nœud. L'option -L les affiche en colonnes :
kubectl get nodes -L kubernetes.io/arch -L kubernetes.io/osNAME STATUS ROLES VERSION ARCH OSk3d-cairn-server-0 Ready control-plane,master v1.31.5+k3s1 amd64 linuxLe réflexe moderne : les images multi-architecture
Section intitulée « Le réflexe moderne : les images multi-architecture »C'est le point que beaucoup de vieux tutoriels ratent. Une image multi-architecture embarque une manifest list (un index OCI) qui pointe vers une variante par plateforme. Quand un nœud tire l'image, le registre renvoie l'index et Kubernetes choisit automatiquement la variante de l'architecture du nœud. Inspectez n'importe quelle image officielle :
docker buildx imagetools inspect nginx:1.27-alpineMediaType: application/vnd.oci.image.index.v1+json Platform: linux/amd64 Platform: linux/arm/v6 Platform: linux/arm64 ...Conséquence directe : avec une image multi-arch (la plupart des images officielles le sont), vous n'avez aucun nodeSelector à écrire. Le même Deployment tourne sur vos Pi et vos x86, chacun tirant sa variante. Pour vos propres images, construisez-les multi-arch avec buildx :
docker buildx build --platform linux/amd64,linux/arm64 --push -t monorg/monimage:1.0 .Le --push est requis : le driver docker-container pousse directement la manifest list au registre.
Cibler une architecture quand c'est nécessaire
Section intitulée « Cibler une architecture quand c'est nécessaire »Le ciblage explicite ne sert que dans deux cas : une image mono-architecture, ou un placement délibéré (réserver les Pi à certains workloads). La forme la plus simple est nodeSelector :
apiVersion: apps/v1kind: Deploymentmetadata: name: web-armspec: replicas: 1 selector: matchLabels: { app: web-arm } template: metadata: labels: { app: web-arm } spec: nodeSelector: kubernetes.io/arch: arm64 containers: - name: web image: nginx:1.27-alpinenodeSelector est une contrainte dure et n'accepte qu'une égalité. Pour autoriser plusieurs architectures, passez à nodeAffinity avec l'opérateur In :
spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: ["amd64", "arm64"]Les deux formes ont été validées en lab (rollout réussi). Retenez la distinction : required... est une contrainte dure (le pod reste Pending si rien ne correspond), tandis que preferred... (pondéré de 1 à 100) n'est qu'une préférence, le pod est placé ailleurs à défaut.
Isoler des nœuds avec taints et tolerations
Section intitulée « Isoler des nœuds avec taints et tolerations »Pour qu'un nœud ARM ne reçoive que des workloads explicitement autorisés (les Pi sont lents, on veut les réserver), tachez-le (taint) :
kubectl taint nodes rpi-01 arch=arm64:NoSchedulePlus aucun pod n'y est planifié, sauf ceux qui portent la toleration correspondante :
spec: tolerations: - key: "arch" operator: "Equal" value: "arm64" effect: "NoSchedule"Différence à garder en tête : nodeSelector/nodeAffinity attirent un pod vers des nœuds ; les taints repoussent les pods d'un nœud. On les combine souvent (cibler l'arch et tolérer le taint).
Pièges du multi-architecture
Section intitulée « Pièges du multi-architecture »| Symptôme | Cause | Solution |
|---|---|---|
exec format error puis CrashLoopBackOff | image compilée pour une autre architecture | utiliser une image multi-arch, ou cibler l'arch de l'image |
| Image qui marche en dev, casse sur le cluster | QEMU émule l'ARM sur votre Mac, pas sur les nœuds | tester sur du matériel natif |
Pod Pending sans raison | nodeSelector d'une arch absente du cluster | vérifier kubectl get nodes -L kubernetes.io/arch |
| Image arm64 refusée sur un Pi | l'OS du Pi est en 32 bits (arm, armhf) | réinstaller un OS 64 bits, ou viser arm |
Le exec format error est le plus fréquent : c'est le noyau qui ne sait pas exécuter un binaire d'une autre architecture. La parade est toujours la même, l'image multi-architecture.
À retenir
Section intitulée « À retenir »- k3s gère nativement AMD64, arm64 et armhf ; l'agent détecte son architecture, aucun paramètre à passer.
- Le kubelet pose
kubernetes.io/archautomatiquement (beta.kubernetes.io/archest déprécié). - Les images multi-architecture sont la clé : Kubernetes tire la bonne variante par nœud, sans
nodeSelector. - Construisez vos images multi-arch avec
docker buildx build --platform linux/amd64,linux/arm64 --push. - Ciblez une architecture avec
nodeSelector(simple) ounodeAffinity(plusieurs arch,In) seulement si l'image est mono-arch ou pour un placement voulu. exec format error+ CrashLoopBackOff = mauvaise architecture d'image ; la réponse est l'image multi-arch.