K3S sur un cluster de Raspberry Pi
Afin de présenter à des étudiants les avantages et inconvénients d’une architecture microservices, j’ai voulu déployer sur un cluster de Raspberry Pi 3 B des instances de k3s, une version allégée de Kubernetes, pour illustrer les capacités de scalabilité et de résilience d’un orchestrateur de conteneurs. Je vous propose de m’accompagner dans l’installation et la configuration de celui-ci, avec son lot de déconvenues et, je l’espère, d’astuces qui pourront vous aider si vous tenter l’expérience vous-même.
Le matériel
Le matériel que j’ai utilisé (un kit Pico 5), initialement prêté à @eric_briand pour expérimenter sur l’éco-conception logicielle, se compose des éléments suivants :
- 5 Raspberry 3B et des cartes SD 64Go pour héberger les OS et systèmes de fichiers
- une alimentation externe
- un switch réseau pour connecter les nodes entre eux
- une prise RJ45 externe pour se connecter au switch en Ethernet
La prise réseau externe fut particulièrement utile à des fins de configuration ou pour se connecter directement au master sans passer par le réseau local, comme nous le verrons après.
Le tout est présenté dans un boîtier en plaques acryliques à monter soi-même, ce qui permet d’apprécier les lumières clignotantes du cluster et remplace aisément un sapin en ces périodes de fêtes (bon, j’ai en effet un peu de retard dans la livraison de cet article…).
Installation de l’OS
Afin de profiter d’un OS maintenu à jour avec la Raspbian Lite (distribution Linux très légère à destination des processeurs ARM) et disposant d’outils de configuration et de conteneurisation, le choix s’est porté sur HypriotOS. Cette distribution orientée conteneurs comprend cloud-init qui m’a été fort utile pour l’initialisation et la configuration du Wi-Fi. L’utilisation de l’outil flash, fourni par Hypriot, avec l’ajout d’un hostname et l’utilisation d’un fichier user-data personnalisé a permis de démarrer les différents Raspberry et de les connecter à notre réseau local afin de poursuivre l’installation.
Exemple d’une commande pour flasher l’image sur la carte SD :
flash -n master -u wifi-user-data.yaml https://github.com/hypriot/image-builder-rpi/releases/download/v1.11.0/hypriotos-rpi-v1.11.0.img.zip
Le fichier wifi-user-data.yaml est une version modifiée de celui-ci avec nos paramètres Wi-Fi. Préciser le hostname avec l’option -n surcharge l’information contenue dans le fichier user-data.
Pour mon installation, j’ai utilisé les noms suivants pour différencier les nodes du cluster: master, node01, node02, node03 et node04. L’avantage de les nommer est de pouvoir les retrouver simplement via ssh pour lancer l’installation de k3s, comme nous allons le voir juste après.
Mise en place du serveur k3s
Mettons maintenant en place le serveur sur le node master. Il faut pour cela se connecter en ssh à celui-ci: ssh pirate@master.local (password: hypriot)
Les identifiants et mots de passe peuvent être changés via le fichier user-data à l’initialisation du Raspberry. J’ai laissé les valeurs par défaut pour des raisons de simplicité dans un premier temps, mais il est évidemment nécessaire de créer des utilisateurs avec des mots de passe différents et robustes pour chacun des nodes. Par défaut les Raspberry sont accessibles via ssh avec <identifiant>@<hostname>.local tel que nous les avons configurés précédemment.
Le script d’installation fourni par Rancher sur le repo Github de k3s permet de récupérer automatiquement l’exécutable adapté à l’architecture ainsi que divers utilitaires et scripts pour gérer le service :
curl -sfL https://get.k3s.io | sh -
Il est bien entendu recommandé de jeter un œil sur le script install.sh avant de l’exécuter dans un shell sur votre machine.
Le lancement du serveur k3s va être ajouté en tant que service dans systemd, ce qui permettra son démarrage automatique au branchement du Raspberry ou lors d’un reboot.
On notera l’existence d’un script k3s-killall.sh, qui arrête tous les processus système liés à k3s afin de relancer proprement l’exécutable, une commande que j’aurais beaucoup utilisée lors de l’installation et de la configuration des agents k3s.
Mise en place des nœuds k3s
Afin d’installer et de configurer correctement k3s sur les autres Raspberry, il nous faut récupérer le token généré par le serveur à son installation, ainsi que l’adresse IP de celui-ci. Et c’est à ce moment-là que les ennuis ont commencé pour moi… La récupération du token est aisée, une simple commande sudo cat /var/lib/rancher/k3s/server/node-token sur le master l’affiche. Nous le passerons en variable d’environnement au lancement de l’agent. Pour la récupération de l’IP du serveur c’est une autre histoire. Il m’a fallu de nombreux tâtonnements et moult ifconfig sur le master avant de comprendre que je devais utiliser l’adresse associée au Wi-Fi pour connecter les agents au master :
ifconfig wlan0 | grep -w inet | awk '{print $2}'
curl -sfL https://get.k3s.io | K3S_URL=https://<ip_wlan_du_noeud>:6443 K3S_TOKEN=<node_token> sh -
Ces commandes devraient lancer le téléchargement et la configuration des agents. Une fois terminé il est possible de vérifier le bon fonctionnement de ceux-ci en se connectant sur le master et en lançant la commande :
sudo kubectl get nodes
On notera que j’ai commencé à assigner des labels au différents nœuds et master à l’aide de la commande sudo kubectl label node <hostname> kubernetes.io/<master_or_node> depuis le master.
Il est possible (ce fut le cas pour moi à de multiples reprises…) que malgré une installation sans problème, ou lors du redémarrage du cluster, les nodes ne parviennent pas à se connecter au master, pour des raisons que j’ignore. Ma solution, un peu cavalière, j’en conviens, mais d’une efficacité redoutable : se connecter en ssh au node et reboot!! lancer les commandes suivantes :
sudo k3s-killall.sh
sudo k3s agent -server https://<ip_wlan_du_noeud>:6443 -token <node_token>
A ce sujet, il devient fastidieux de changer de machine en ssh ou de naviguer entre les différent terminaux dans tmux, aussi je vous propose d’installer kubectl et de le configurer pour accéder à notre cluster. Pour pouvoir agir sur le master de façon transparente, il nous reste à récupérer la configuration du cluster sur celui-ci, modifier l’adresse du serveur et nommer le fichier .kube /config dans votre répertoire personnel. J’ai utilisé scp pour copier le fichier via ssh :
scp pirate@master.local:/etc/rancher/k3s/k3s.yaml .
Vous devrez remplacer ‘127.0.0.1’ par l’adresse ip wlan du master à ligne “server : https://127.0.0.1:6443”
Puis renommer et déplacer le fichier :
mv k3s.yaml ~/.kube/config
Cela va nous permettre de lancer toutes les commandes depuis notre machine favorite, sans sudo et nous simplifiera la vie pour lancer et accéder au Dashboard.
Installation du Dashboard
Commençons par déployer les éléments nécessaires avec la commande :
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
Et vérifions que tout s’est déployé correctement :
kubectl get all -n kubernetes-dashboard
Nous devons ensuite créer un ServiceAccount et un Role pour avoir le droit d’accéder au Dashboard et d’effectuer des modifications ou des déploiements sur le cluster :
cat >> dashboard-adminuser.yaml <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard EOF
Puis appliquer les modifications :
kubectl apply -f dashboard-adminuser.yaml
Il nous faut ensuite utiliser la commande kubectl proxy &, ce qui va exposer celui-ci à l’adresse suivante, accessible dans notre navigateur web : http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
Attention, le dashboard ne sera accessible que depuis la machine sur laquelle la commande de proxy a été lancée.
Reste à se connecter à celui-ci avec le token lié au serviceAccount créé précédemment. La commande suivante permet de récupérer le token :
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
Copiez et collez la valeur de celui-ci dans le champ “Saisissez un jeton” :
You’re in, well done! On peut maintenant aller vérifier la bonne santé de nos nodes.
Pour conclure
A posteriori, je me rends compte qu’une meilleure connaissance des problématiques d’adressage réseau et du fonctionnement interne du cluster m’aurait probablement évité de m’arracher les cheveux (qu’il me reste) sur la connexion des agents au serveur.
Après consultation des collègues plus au point que moi sur le sujet, une solution à envisager pour éviter de dépendre du réseau local et d’une connexion Wifi est de se connecter en Ethernet et d’utiliser son poste de travail comme serveur DHCP. Cela permettrait de s’abstraire de la configuration du Wi-Fi faite en début d’article et de s’assurer de toujours pouvoir communiquer avec le cluster.
Enfin malgré tous mes efforts, je n’ai toujours pas réussi à adapter un des projets cités ci-dessus à k3s, mes pods tombant presque tous dans l’enfer du CrashLoopBackoff. Malgré ces écueils, l’installation est assez aisée et permet de monter rapidement un environnement de démonstration pour les fonctionnalités d’un orchestrateur et les avantages et inconvénients d’une architecture microservices.
Un grand merci à @pyaillet et @eric_briand pour leur conseils avisés.
Sources:
https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard
https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md