L'apprentissage à la dure
Post-mortem des incidents de février 2025.
Comme toujours, c'est à la lumière du jour qu'on voit mieux les craquelures. Un système, même idéalement conçu, présente toujours des défauts d'architecture et d'implémentation, qui ne seront découverts qu'en production.
Le 10 décembre dernier nous vous évoquions les difficultés de la fin d'année 2024. Nous y faisions état d'un cluster qui ne réagissait plus automatiquement aux pertes de nœud, c'est corrigé depuis. Nous y évoquions également nos difficultés à équilibrer le cluster, se soldant par l'ajout de nœuds à venir pour moins souffrir en cas de défaut de l'un de nos sites.
Depuis le 20 février au soir, nous avons à nouveau d'importants défauts sur notre infrastructure, qui mettent à nu des problèmes de conception connus, mais aussi de nouveaux sujets.
Il a Free, il change de FAI
La zone fr-kai-1
est hébergée chez Free. Du moins, était hébergée chez Free jusqu'au 20 février. Entre octobre et décembre nous avions déjà fait face à 5 incidents Free, dont une panne de 5 jours complets sur la zone. Nous pensions être sortis d'affaire après le changement d'OLT dans le NRO de Free, mais rebelote : le 20 à 15h30 coupure franche du lien, toujours un signal mais pas de négociation EPON et donc probablement un défaut au NRO.
En prévision d'une future bascule, nous avions déjà souscrit sur la zone un accès Internet par MilkyWan, un FAI associatif ayant de bons partenariats pour la collecte FTTH (même s'ils ne sont pas membres FFDN). Le lien était livré depuis 3 jours, actif sur le site mais les serveurs n'avaient pas basculé dessus.
La soirée de jeudi a globalement consisté à : – faire le constat de l'incident ; – gérer la bascule des services principaux sur d'autres sites ; – activer l'IPv6 sur l'accès MilkyWan ; – affecter le nouveau préfixe sur les serveurs et les nœuds hepto ; – réinsérer les nœuds dans le cluster sur leur nouveau WAN.
L'incident n'était véritablement clos que le lendemain, le temps de reconfigurer nos passerelles NAT64 pour prendre en compte ce nouveau site (simplement parce qu'on filtre les accès NAT64, évitant d'en faire des open proxies).
Free est depuis résilié sur la zone, bientôt la documentation à jour.
Il a SFR, c'est l'enfer
La zone fr-kai-2
est hébergée chez SFR. Depuis le 21 février au soir au moins, et encore plus franchement depuis le 22 après-midi, son accès WAN est très dégradé : un débit franchement limité et des pertes régulières de paquets (jusqu'à 500ms de jitter et 30% de perte de paquets).
Cette panne, moins franche, est d'autant plus vicieuse. Les premiers symptômes sont apparus alors même qu'on restaurait le NAT64 suite à la bascule de fr-kai-1
. Il a fallu du temps pour la détecter et la qualifier, et elle a eu des impacts absolument inattendus.
Nous n'avons pas encore identifié la cause racine de cet incident, quoi qu'il ressemble fort à un engorgement de routeur : dès que le taux de paquets augmente, le taux d'erreur et la latence également. Le souci est mis de côté : fr-kai-2
est temporairement fermé au public le temps qu'on intervienne.
Le meilleur enseignement reste celui des effets de bord.
Le système qui s'emballe
Dès le 21 au soir la zone était défaillante, mais c'était encore beaucoup plus marqué le 22 dans la journée. Nous soupçonnons que notre cluster Garage (S3 distribué) est pour partie responsable de la surcharge : les réplications échouées vers fr-kai-2
sont retentées en boucle jusqu'à engorger encore plus le tuyau. Nous ne mesurons pas à quel point faute de disposer des métriques pour.
La part le plus belle est toutefois attribuable à nos mécanismes de sauvegarde. D'une part nous employons CNPG pour les bases de données, qui sauvegarde ses WAL sur S3, dont un tiers environ sur fr-kai-2
, et dont les requêtes sont retentées en boucle.
D'autre part, chaque nuit nous synchronisons une part de nos buckets S3 de production vers la zone fr-hal-1
grâce à Higlo, notre automatisation autour de rclone. En pleine journée, des jobs de synchronisation générés par Higlo tournaient toujours :
storage-backups higlo-sync-backup-gitlab-artifacts-28997280 Complete 0/1 44m 5d13h
storage-backups higlo-sync-backup-gitlab-dependency-29001630 Running 0/1 14h 2d13h
Deux indices ici concernant le job de synchronisation du bucket de dépendances de Gitlab : – il tourne depuis 14h alors que c'est un petit volume synchronisé, il est clairement étranglé ; – le job a plus de 2 jours, donc il a déjà échoué, et été relancé, un motif qui n'est pas sans rappeler les deux précédents.
Nous avons temporairement interrompu toutes les tâches de sauvegarde en conséquence, le temps de comprendre l'origine du défaut.
L'APIServer qui pleure
Nous connaissons l'un des défauts majeurs de l'architecture de Hepto, notre distribution kubernetes : il est pour l'instant déployé avec un seul nœud de control plane, donc ni résilience ni répartition de charge sur cette fonction. C'est généralement assez anodin : une panne franche de quelques minutes passe inaperçue, mais c'est bien plus délicat quand les pannes sont plus longues ou moins franches.
L'APIServer est le principal composant de kubernetes : il expose les objets et permet aux contrôleurs de les consulter et les mettre à jour. Un APIServer indisponible c'est pas fabuleux, un APIServer qui clignote, c'est le début de la fin. Et depuis les difficultés de 2024, notre APIServer était sur... fr-kai-2
!
De jeudi soir à samedi après-midi nous avons constaté plusieurs dizaines de défauts de notre ingress controller (traefik), le composant qui accepte les connexions Web. Résultat, tous les sites inaccessibles pendant plusieurs secondes à chaque fois. Nous avons initialement mal qualifié ce problème, constatant côté utilisateur que Matrix devenait inaccessible alors que notre serveur Matrix n'est pas sur le cluster. Puis nous avons révisé l'interprétation, c'est le Matrix Authentication Service sur le cluster qui devenait inaccessible et empêchait Element de fonctionner.
La causalité est probablement très simple :
– le site fr-kai-2
s'emballe ;
– l'APIServer devient largement indisponible (lenteurs, timeouts) ;
– traefik requête l'APIServer pour avoir la liste des URL à exposer ;
– il reçoit une erreur, ou pire une liste vide ;
– il cesse de répondre aux requêtes entrantes jusqu'à ce que l'APIServer lui réponde correctement à nouveau.
Samedi soir nous avons déplacé l'APIServer sur fr-kai-1
, résorbant la plus grande partie de ce problème.
Nous utilisons également Kyverno sur notre cluster, pour contrôler les requêtes et automatiser quelques déploiements. Il s'agit d'un admission controller, placé en coupure e l'APIServer. Hors il est hébergé sur le cluster, et certains de ses composants étaient sur fr-kai-2
, il était donc probablement lui aussi fautif d'une partie des erreurs.
Le DNS au tapis
Nous n'attendions pas ce dernier défaut, pourtant très prévisible et très vicieux. L'infrastructure ne s'arrête pas à lancer des workloads et les mettre en réseau : il faut généralement qu'elles communiquent entre elles. On oublie souvent DNS comme composant central et critique d'une infrastructure, c'est un petit morceau discret dans le démarrage d'un cluster kubernetes, et pourtant.
Déjà en 2024 nous avions rencontré des difficulté avec CoreDNS, l'implémentation DNS de référence pour kubernetes. Pas que CoreDNS fasse défaut mais que nous déployions seulement 2 réplicas, parfois démarrés sur le même site, et la fonction souffrait en cas de panne réseau sur le site par exemple. C'était censément résolu depuis que nous avons basculé le déploiement CoreDNS en DaemonSet
, un mode de déploiement kubernetes qui planifie un Pod
par nœud du cluster.
La logique intuitive est simple : chaque nœud ayant son propre CoreDNS, tout ce qui est lancé dessus pourra en bénéficier en faisant fi de l'état du reste du cluster. Cela dépend d'une fonctionnalité de kubernetes nommée Topology Aware Routing, que nous avions étudiée dès 2019 pour éviter de traverser le WAN à chaque requête vers Garage notamment.
Deux problèmes à cette vision intuitive :
– le topology aware routing, ça s'active et nous ne l'avons jamais fait, donc il est en réalité inactif sur notre cluster ;
– le DaemonSet
que nous avons activé est nativement plus vicieux qu'autre chose, puisque ses Pods
restent actifs même lorsque le nœud est vidé ou en panne.
Résultat : une partie du trafic DNS était dirigé vers CoreDNS sur fr-kai-2
, et ne répondait plus ou mal, rajoutant du bruit à l'APIServer déjà en mauvais état, même après que nous avions désactivé les nœuds concernés.
La suite des opérations
A l'issue de la phase difficile de l'incident, nous avons :
– fr-kai-2
coupé du monde, ses nœuds complètement éteints ;
– le reste du cluster légèrement chargé mais sans plus ;
– la réplication Garage sur 2 pattes et donc vulnérable à toute panne d'une autre zone ;
– des réplicas de base de données toujours en synchronisation pour retrouver une résilience, certains même en panne dû à un cas aux limites de l'utilisation de CNPG.
Les prochaines étapes de remédiation immédiate sont donc :
– étudier CNPG et la configuration des affinités qui semblent empêcher certains nœuds de démarrer sans raison apparente ;
– le rétablissement de tous les réplicas de base de données, en particulier pour TTRSS, qui doit certes fermer ses portes, mais qui devrait continuer de fonctionner quelques jours encore ;
– le diagnostic du WAN de fr-kai-2
avec SFR pour rétablir un service et réactiver les deux nœuds concernés.
Les enseignements complémentaires doivent faire l'objet de travaux :
– c'est du long court, mais déjà démarré avec un refactoring en cours, supporter le multi-control-plane kubernetes dans hepto et déployer avec un control plane sur trois zones ;
– redéployer CoreDNS dans un mode Deployment
avec des contraintes d'affinité garantissant une continuité de service sans subir les désagrément d'un DaemonSet
;
– comprendre comment déployer des DaemonSet
en stoppant les déploiements lorsque le nœud est inaccessible, en particulier pour Garage afin d'éviter de perdre une part de trafic lorsqu'un nœud est indisponible.
Et plus généralement : donner du temps et de l'air à l'équipe infrastructure.
A l'aide !
TeDomum, ce fut près de 10 personnes actives un temps, plus généralement 6 à 8 membres de l'équipe aux meilleurs moments. Aujourd'hui notre infrastructure est plus libre, autonome, éthique, mais aussi plus complexe qu'il y a 3 ans.
Nous sommes principalement 5, 6 les bonnes semaines. 3 d'entre nous sommes plongés dans l'infrastructure et 2 auprès des utilisateurices de nos services. C'est trop peu. Les acteurs de l'infrastructure donnent les coups de main nécessaires à l'administration des services, plus ponctuellement en support de proximité, mais généralement nous n'avons plus collectivement la force d'assurer à la fois une infrastructure qui tourne et des services de qualité au quotidien.
Si vous avez une expérience ou une envie de faire du support de proximité, de la médiation ou de la modération ; si vous avez déjà des connaissances en administration système, idéalement sur kubernetes, vous êtes peut-être nos sauveuses et sauveurs. Si vous avez en prime envie de travailler dans une équipe d'excellente humeur mais globalement débordée, et donc pas peur d'être accueillies et intégrées avec peu de formes et un accompagnement modeste au début (soyons honnêtes), alors définitivement venez nous contacter sur Matrix.