Kubernetes (k3s) en auto-hébergement

Je commence à passer une partie de mon auto-hébergement sous Kubernetes, toujours sur mes petits serveurs Olinuxino A20 et A64.

J’ai choisi d’utiliser k3s, une distribution Kubernetes plus adaptée à mes petites machines, car moins consommatrice en ressources (tout en étant certifiée Kubernetes).

Control-plane k3s

Installation

(édité le 13/01/2022 pour présenter les solutions avec containerd ou avec docker)

Avec Containerd

C’est ce qui utilisé par défaut par k3s, et recommandé (parce qu’il est probable que le support de docker par k3s disparaisse dans quelques versions, cf https://github.com/k3s-io/k3s/issues/4859#issuecomment-1008141642). Pas la peine d’installer containerd, il est déjà fourni dans le binaire de k3s :

sudo apt install curl
curl -sfL https://get.k3s.io | sh -s -

(j’aurais préféré un .deb, mais bon…)

Avec Docker

sudo apt install docker.io curl
curl -sfL https://get.k3s.io | sh -s - --docker

Sur debian bullseye, le démarrage de k3s plante sur l’erreur suivante (on la trouve dans /var/log/syslog) :

failed to run Kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd"

Pour régler cette erreur, il faut modifier ou créer le fichier /etc/docker/daemon.json avec le contenu suivant :

{
  "exec-opts": [
    "native.cgroupdriver=cgroupfs"
  ]
}

puis faire un « systemctl daemon-reload », puis un « systemctl restart docker ». Cf https://github.com/k3s-io/k3s/issues/797.

Consommation de ressources

Même avec k3s, le serveur control-plane consomme beaucoup, même au repos.

Le processus k3s écrit en continu sur le filesystem. Environ 45Ko/s, sur /var/lib/rancher/k3s/server/db/state.db* : la base de données SQLite utilisée à la place de etcd. Kubernetes fonctionne effectivement en « append-only » sur sa base de données. Et encore, l’équipe de k3s a apporté des optimisations pour réduire la quantité d’I/O (qui serait encore plus importante avec etcd).

Le processus k3s d’un control-plane consomme aussi autour de 35% d’un coeur du CPU A64 (ou plus d’un coeur complet du CPU A20), et 550Mo de RAM : ce n’est pas rien.

Cette consommation de ressources a été discutée avec les mainteneurs sur https://github.com/k3s-io/k3s/issues/2278 : en résumé, ils ne peuvent pas vraiment descendre en-dessous sans perdre les fonctionnalités essentielles de kubernetes. Ils ont aussi une page décrivant les ressources minimum réclamées par k3s : https://rancher.com/docs/k3s/latest/en/installation/installation-requirements/resource-profiling/.

J’ai d’abord essayé d’utiliser un A20 pour ce control-plane mais c’est bien trop lent : environ 30 minutes pour que les pods internes à k3s démarrent, beaucoup de timeouts, et kubectl met très longtemps à répondre (6 à 20 secondes à chaque appel ou auto-completion)

Sur A64, le temps de réponse de kubectl devient acceptable. Pour préserver ce control-plane, je lui ai ajouté le taint « node-role.kubernetes.io/master:PreferNoSchedule » (il ne l’a pas toujours par défaut) : cela évite qu’il y ait d’autres pods qui tournent dessus.

Un ou plusieurs control-planes?

k3s (comme le kubernetes « normal ») permet d’avoir plusieurs control-planes, pour de la haute-disponibilité. Je l’ai envisagé mais cela obligerait à utiliser etcd plutôt que sqlite. Or etcd consomme bien trop de ressources (notamment I/O disques) pour ces petites machines avec filesystem sur carte SD. C’est précisé en avertissement au tout début de https://rancher.com/docs/k3s/latest/en/installation/ha-embedded/, et on voit des expériences malheureuses sur le bugtracker : https://github.com/k3s-io/k3s/issues/2615.

Je reste donc sur un seul control-plane pour l’instant, avec des sauvegardes quotidiennes de /var/lib/rancher/k3s (dans lequel se trouve la base SQLite). J’ai testé une restauration : il suffit de restaurer le répertoire au même endroit avant de réinstaller k3s, et le control-plane retrouve ses données.

Si mon control-plane devient inaccessible, les services qui tournent dans le cluster continuent de fonctionner (j’ai testé). Par contre, ils ne sont plus « pilotés » (surveillance, scaling etc), et kubectl ne fonctionne bien sûr plus (ce qui peut être très handicapant).

Pour limiter ce problème (si la machine de mon control-plane devient injoignable, par exemple), j’ai utilisé un alias DNS pour le control-plane, qui peut être basculé sur une autre machine si besoin, comme suggéré sur https://github.com/k3s-io/k3s/issues/2031#issuecomment-660402759.

En cas de gros pépin sur le control-plane, ma procédure est donc de restaurer une sauvegarde de /var/lib/rancher/k3s sur une autre machine, d’y installer k3s (en mode control-plane) et de basculer mon alias DNS dessus.

Autres noeuds k3

Sur chacun des autres noeuds, l’installation se fait avec :

sudo apt install curl
curl -sfL https://get.k3s.io | K3S_URL=https://alias-dns-control-plane:6443 K3S_TOKEN=K101bfdda519dc15b3c9400bf91d8ea70961152d44f686bc3feee481481f76157ad::server:01ad7a756859e4a9133a7ebd2c5d54cc sh -s -

(le token étant à récupérer dans le fichier /var/lib/rancher/k3s/server/node-token du control-plane et à remplacer dans la ligne de commande ci-dessus)

Pour utiliser docker au lieu de containerd, il faut installer aussi le package docker.io, et ajouter  » –docker » à la fin de la seconde ligne. Il peut y avoir besoin aussi de créer/modifier le fichier /etc/docker/daemon.json (comme pour le control-plane ci-dessus)

Sur un A64, l’agent consomme 7% d’un coeur de CPU et 150 Mo de RAM (mais pas d’I/O disque). Sur un A20, l’agent consomme 20-25% d’un coeur de CPU et autant de RAM.

J’ai mis 2 taints sur les noeuds A20 : d’abord parce qu’ils utilisent une architecture armhf, pour laquelle il y a rarement des images Docker, et ensuite parce que les performances y sont bien moindres. Ca me permet de choisir quels pods tourneront dessus, en leur ajoutant les tolerations qui vont bien.

J’ai aussi intégré dans ce cluster de vieux PCs (a priori temporairement), en architecture amd64.

Instabilités après quelques jours à cause de la version d’iptables

Pendant un bon moment, j’ai eu des problèmes de stabilité sur mes nodes k3s : au bout de quelques jours, ils se mettaient à beaucoup ralentir, à cause de processus iptables qui consommaient tout le CPU.

En contournement, j’avais mis un crontab pour un redémarrage quotidien de chaque machine : efficace mais clairement pas optimal…

Il s’agit en fait d’un problème lié à la version d’iptables fournie avec Debian 10 Buster (et d’autres OS aussi) : https://github.com/k3s-io/k3s/issues/3117. Le contournement proposé (désinstaller iptables) n’étant pas compatible avec l’utilisation de fail2ban, j’ai préféré mettre à jour (ou réinstaller) mes machines vers Debian 11. Ca a suffit à rendre les machines à nouveau stables (et, au passage, a fourni des versions plus récentes du kernel et de docker)

Disponibilité d’images Docker pour l’architecture arm

La plupart des images « de base » (celles des principales distributions linux, des principaux serveurs HTTP, d’application, de base de données etc) sont proposées en architecture arm et/ou arm64 (en plus de l’omniprésente architecture amd64).

Mais c’est beaucoup plus rare pour les images « applicatives », qui embarquent autre chose que de l’infrastructure.

A l’heure actuelle, quasiment aucun chart Helm de Bitnami ne fonctionne sur architecture arm : ils ne créent des images que pour l’architecture amd64.

Même chose pour quasiment tous les projets disponibles sur https://artifacthub.io/.

Il y a des demandes régulières pour cela : Bitnami travaille dessus, mais ce c’est pas fait pour l’instant. Cf https://github.com/bitnami/charts/issues/7305.

On sent pourtant qu’il y a une pression de plus en plus forte des utilisateurs pour avoir des images arm (au moins arm64). Probablement « grâce » au processeur M1 d’Apple, mais aussi parce que les clouds publics commencent à en proposer (pour certains depuis longtemps, d’ailleurs), et que leur faible consommation énergétique peut être déterminante.

Patience, donc : je ne doute pas que la majeure partie des produits open-source auront bientôt une image arm ou arm64.

A venir

Je prépare d’autres articles sur ce sujet : ce que j’ai déployé sur ce cluster, comment gérer le stockage persistent etc.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *