Introduction Link to heading
Ma première installation de kubernetes a été faite dans sa version 1.12 ou 1.13. C’était d’ailleurs déjà sur mon petit cluster d’odroid-c2. À l’époque kubernetes ne supportait pas encore arm64 et je passais plus de temps dans le code de kubelet à le patcher et à le recompiler qu’à déployer des choses. Autant dire qu’avec le cycle de livraison court de kubernetes, ce cluster a vu passer pas mal de versions et beaucoup de changements.
Outre les versions de kubernetes, pendant ces quelques années il y a aussi eu beaucoup de mises à jour du kernel linux et d’autres librairies. Certaines de ces mises à jour nécessitent des redémarrages et, pour un cluster kubernetes, ça sous-entend de passer sur chaque nœud tour à tour pour effectuer un cordon & drain & reboot & uncordon afin d’éviter le downtime des applications qui y sont hébergées.
Ces tâches de maintenance deviennent rapidement fastidieuses mais heureusement peuvent être automatisées à l’aide de Kured.
Kured Link to heading
Kured (KUbernetes REboot Daemon) is a Kubernetes daemonset that performs safe automatic node reboots when the need to do so is indicated by the package management system of the underlying OS.
Très simplement, Kured est un outil déployé en DaemonSet dans le cluster qui vérifiera la présence d’un fichier posé par le gestionnaire de packets indiquant la nécessité de redémarrer la machine (cette vérification pourra aussi être effectuée à l’aide d’une commande personnalisée).
La force de Kured, c’est de pouvoir s’occuper de cordon, drain et uncordon proprement les nœuds avant de les redémarrer, chacun leur tour. Dans des utilisations plus complexes, il peut aussi vérifier le statut de certaines alertes prometheus ou encore la présence de certains pods afin de repousser un redémarrage.
Sentinelle Link to heading
Pas de chance, sous archlinux - que j’utilise partout depuis des années car c’est la distribution que je connais le mieux et que je la trouve tout à fait adaptées à un homelab - le gestionnaire de packets ne crée pas de fichier indiquant la nécessité de redémarrer une machine après une mise à jour.
Après avoir utilisé des outils comme longoverdue et grep pour définir si un redémarrage était nécessaire, j’ai écrit un bête script shell :
#!/usr/bin/env sh
if [ ! -f /var/lib/pacman/db.lck ]; then
libs=$(lsof -n +c 0 2> /dev/null | grep 'DEL.*lib' | awk '1 { print $1 ": " $NF }')
if [[ -n $libs ]]; then
exit 0
fi
if [ ! -d "/lib/modules/$(uname -r)" ]; then
exit 0
fi
fi
exit 1
J’utilise toujours longoverdue
pour redémarrer automatiquement les services qui peuvent l’être à la fin de mes
mises à jour, ensuite ce script informera Kured qu’un reboot est nécessaire s’il reste des fd ouverts sur des
libs qui auraient été mises à jour et si le kernel a changé depuis le dernier démarrage.
J’ai laissé un PKGBUILD dans AUR pour faciliter son installation et sa maintenance sur différentes machines.
Automatiser les mises à jour Link to heading
Les paquets kubelet
et kubeadm
n’existaient pas pour l’architecture aarch64
à l’époque où j’ai installé pour la
première fois kubernetes dans mon homelab. Ils ne sont présents que depuis peu dans les dépots de la distribution
archlinuxarm. Les PKGBUILD présents dans AUR ne me convenant pas et divergeant trop, à mon goût, de ce que j’avais
en tête pour eux, j’ai décidé de refaire les miens, qui sont hébergés sur mon dépôt
(avr) :
kubelet-bin,
kubeadm-bin.
Archlinux étant une distribution dont les mises à jour sont en rolling releases, maintenir mes propres paquets me
permet de mettre à jour kubernetes à la fréquence qui me convient. Pour cela, je fais ignorer les mises à jour de
kubeadm et kubelet dans /etc/pacman.conf
et je ne modifie mes PKGBUILD et build les nouvelles versions des paquets
que lorsque j’en ai besoin.
[options]
IgnorePkg = kubelet-bin kubeadm-bin
Ce paramètre me permet donc de mettre à jour (presque) sans risque les différents nœuds de mon cluster automatiquement.
Maintenant que la stabilité des mises à jour est relativement assurée, il ne reste plus qu’à automatiser les mises à jour des machines. J’utilise sur les nœuds des points de montagne NFS pour les dossiers contenant le cache de paquets ainsi que pour les fichiers de db des différents dépots, ce qui me permet de ne télécharger qu’une seule fois les mises à jour et d’en profiter sur toutes les machines.
Sur la machine mettant à jour le cache de paquets :
# /etc/systemd/system/pacman-cache-update.service
[Unit]
Description=Download package updates
ConditionPathIsMountPoint=/var/lib/pacman/sync
ConditionPathIsMountPoint=/var/cache/pacman/pkg
After=network-online.target nss-lookup.target
Wants=network-online.target
[Service]
Type=oneshot
Nice=19
ExecStart=/usr/bin/pacman -Syuw --noconfirm --noprogressbar
Restart=no
# /etc/systemd/system/pacman-cache-update.timer
[Unit]
Description=Download package updates daily
[Timer]
OnCalendar=*-*-* 12:00:00
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Sur tous les hôtes :
# /etc/systemd/system/pacman-upgrade.service
[Unit]
Description=Upgrade packages
ConditionPathIsMountPoint=/var/lib/pacman/sync
ConditionPathIsMountPoint=/var/cache/pacman/pkg
After=network-online.target nss-lookup.target
Wants=network-online.target
[Service]
Type=oneshot
Nice=19
ExecStart=/usr/bin/pacman -Su --noconfirm --noprogressbar
Restart=no
# /etc/systemd/system/pacman-upgrade.timer
[Unit]
Description=Upgrade packages daily
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=false
[Install]
WantedBy=timers.target
Installation Link to heading
L’installation de Kured est très simple. En utilisant son chart
helm, le seul paramètre qu’il est nécessaire de renseigner est la commande que chaque pod du DaemonSet exécutera grâce
à nsenter
sur son hôte. Par défaut, Kured lancera le script toutes les heures.
helm upgrade \
--install \
--namespace kured-system \
--create-namespace \
--set configuration.rebootSentinelCommand=/usr/bin/kured-sentinel \
kured kubereboot/kured
Pour aller plus loin Link to heading
Imaginez maintenant un monde parfait dans lequel toutes les applications sur vos clusters sont correctement configurées avec des sondes de liveness, readiness et startup, des règles d’affinité demandant le démarrage des différents réplicas sur différentes machines, répliquées quand c’est possible et tolerant les perturbations à l’aide de définitions de PodDisruptionBudget.
Les mises à jour des machines sont lancées dans des tâches planifiées et lorsque l’une d’elle nécessite un redémarrage, Kured lance le drain du nœud. Les PodDisruptionBudget permettent alors d’être certain que les applications restent disponibles ailleurs. Le nœud peut donc redémarrer puis, un outil comme descheduler pourrait répartir la charge préalablement déplacée sur les autres machines tout en utilisant les ressources de ce nœud fraichement redémarré. Kured préparerait ensuite le reboot des autres nœuds et voilà, vous auriez un cluster qui se maintiendrait à jour avec un minimum d’effort de monitoring de votre part et sans perturbation.