Dans DevOps, l'un des problèmes les plus difficiles est celui de ceux qui bloquent activement leur propre enquête. En lice pour le titre de champion, le deuxième pire type de problèmes est celui qui se produit par intermittence. Cet article est une histoire d'aventure d'une époque où le système d'intégration continue/déploiement continu (CI/CD) en amont de Podman rencontrait les deux simultanément.
Une tempête parfaite
Il était une fois, l'automatisation des tests Podman a commencé à dépasser son pantalon "grand garçon". Cela s'est produit il y a des années, lorsque pratiquement tous les systèmes CI/CD étaient basés sur des conteneurs. Podman, étant un outil de gestion (et de débogage) de conteneur (et de pod), ne peut pas être pleinement exercé dans un conteneur. Pire peut-être, la majorité des services d'automatisation de base ne prenaient en charge qu'Ubuntu. Cela est rapidement devenu un non-démarrage absolu, puisque Podman devait fonctionner sur des machines virtuelles (VM). Il devait également fonctionner avec plusieurs distributions, y compris la distribution en amont de Red Hat, Fedora.
Ayant de l'expérience avec les workflows CI/CD greffés sous une configuration cloud-sdk + SSH (et/ou Ansible) pour l'accès au cloud, la complexité accrue semble toujours poser des problèmes. Puis un jour, je suis tombé sur Cirrus-CI. Cirrus-CI est un outil d'automatisation centré sur Git capable d'orchestrer des conteneurs et des machines virtuelles, en utilisant une pléthore de fournisseurs de cloud. Il a permis à l'équipe Podman de payer et de gérer le service cloud indépendamment de son orchestration. Nous pouvions garder le contrôle total sur les machines virtuelles et les données de journal, Cirrus-CI ne gérant que l'orchestration.
Le flux de travail global ressemble à ceci :
- Un développeur soumet des modifications de code proposées en amont dans le référentiel Git de Podman.
- Cirrus-CI le remarque, lit un fichier de configuration, puis lance les VM nécessaires dans notre cloud.
- Les services de métadonnées cloud natifs gèrent l'exécution des scripts et la reconnexion à Cirrus-CI.
- Cirrus-CI supprime les VM et fournit des commentaires de réussite/échec au développeur.
- Les modifications sont apportées et le cycle se répète jusqu'à ce que le code soit accepté.
Pendant des années, ce flux de travail a fonctionné presque parfaitement, la plupart des problèmes étant centrés sur les tests et les scripts, des défauts que l'équipe Podman gère facilement. Rarement, des problèmes au sein de Cirrus-CI, d'Internet et/ou de notre fournisseur de cloud aboutissent à des machines virtuelles orphelines (à défaut de suppression). Sinon, le personnel d'assistance de Cirrus Labs a été fantastique, très accessible, avec une réactivité et une responsabilité de premier ordre.
Puis un jour d'octobre 2020, après la rotation d'un ensemble d'images de machine virtuelle fraîchement mises à jour (c'est-à-dire l'image disque copiée pour chaque nouvelle instance de machine virtuelle), des tâches apparemment aléatoires ont commencé à échouer. L'enquête initiale sur la sortie du script n'a fourni aucune information. Littéralement, toute sortie s'arrêterait soudainement, sans aucun schéma discernable par rapport aux autres échecs. Comme prévu, Cirrus-CI nettoierait avec diligence la machine virtuelle et présenterait l'échec résultant au développeur pour qu'il le comprenne. Souvent, lors de la réexécution de la tâche ayant échoué, celle-ci réussissait sans incident.
Cette situation s'est poursuivie pendant plusieurs semaines sans problème de correspondance avec les pannes d'infrastructure dans notre cloud, GitHub ou Cirrus. Le problème était quelque peu rare, peut-être une poignée d'échecs par jour, sur des centaines d'emplois réussis. La recherche de pannes était difficile et la réexécution perpétuelle des tâches ne pouvait pas être une solution de contournement à long terme. Outre les rapports d'incidents réguliers de mon équipe, je n'ai pu discerner aucun schéma de haut niveau des échecs. Étant donné que les nouvelles images de VM offraient des avantages significatifs, le coût de la restauration aurait également été élevé.
Pour presque tous les problèmes systémiques comme celui-ci, la recherche de modèles de comportement est un élément clé pour un dépannage réussi. Étant donné que la réussite professionnelle fiable est l'état souhaité, avoir au moins une notion, ou un indice, était une exigence absolue. Malheureusement, dans ce cas, notre capacité à observer les modèles a été extrêmement limitée par les échecs aléatoires et la fonctionnalité hautement souhaitable :le nettoyage des machines virtuelles cloud désaffectées, qui gaspillent de l'argent réel.
L'exécution de tests simples, répétés et manuels n'a pas du tout reproduit le problème. Le fait de lancer plus de ressources CPU et mémoire n'a pas non plus affecté le comportement. J'ai passé des jours à réfléchir et à réfléchir à des options pour recueillir des données supplémentaires associées aux échecs. Enfin, il m'est apparu que j'avais besoin d'un moyen d'interrompre sélectivement le nettoyage de la machine virtuelle, mais uniquement dans les cas où les tests n'ont pas fini de s'exécuter.
[ Vous pourriez également aimer : De l'administrateur système au DevOps ]
En d'autres termes, j'avais besoin d'associer d'une manière ou d'une autre la réussite du test (pas seulement la réussite / l'échec) à l'autorisation du nettoyage. C'est alors que je me suis souvenu d'une petite case à cocher que j'ai vue une fois en fouillant dans l'interface Web de notre cloud :Protection contre la suppression . Lorsque cet indicateur est défini, Cirrus-CI se plaindra bruyamment car il est empêché de supprimer une VM, mais sinon, il ne dérangera rien.
J'avais besoin d'instrumenter notre flux de travail afin que les machines virtuelles elles-mêmes puissent définir et désactiver leur propre indicateur de protection contre la suppression. Quelque chose comme ça :
- VM active la protection contre la suppression sur elle-même.
- Exécuter des tests.
- VM désactive sa propre protection contre la suppression.
- Cirrus-CI nettoie ou ne parvient pas à nettoyer la machine virtuelle et en fait tout un plat.
De cette façon, une fois les tests terminés, Cirrus-CI se fera un plaisir de supprimer la VM comme d'habitude. Cependant, si le problème se produisait, les tests ne se termineraient pas et Cirrus-CI se heurterait à la protection contre la suppression (toujours) activée. Heureusement, ce flux de travail était tout à fait possible à réaliser via de simples options de ligne de commande pour le programme utilitaire de gestion du cloud que je pouvais installer sur les machines virtuelles.
Avec cette instrumentation de flux de travail en place, tout ce que j'avais à faire était de déclencher à plusieurs reprises la matrice de test et d'attendre que les machines virtuelles orphelines s'affichent. Le destin me souriait ce jour-là car le problème s'est reproduit quasi instantanément. Cependant, je l'ai exécuté plusieurs fois de plus, j'aurais donc plus que quelques machines virtuelles orphelines à inspecter.
De manière inattendue, c'est à ce moment que la situation est devenue encore plus intéressante :je ne pouvais pas me connecter en SSH aux VM orphelines. En fait, ils ne répondraient même pas aux pings provenant de l'intérieur ou de l'extérieur de notre cloud. J'ai effectué une réinitialisation matérielle sur une machine virtuelle et vérifié les journaux système une fois qu'elle a démarré. Il n'y avait rien. Zipper. Non. Pas un seul iota d'un indice autre que ce que nous savions déjà :les tests ont simplement cessé de s'exécuter, morts, avec le reste du système.
Comme c'était déjà mon jour de chance, j'ai décidé de le pousser et j'ai de nouveau fouiné dans l'interface Web de mon cloud. Finalement, j'ai trouvé un autre petit paramètre incroyablement pratique :Journal de sortie de la console série . Il s'agissait essentiellement d'une ligne de communication directe de bas niveau directement dans le noyau. Si quelque chose se produisait suffisamment horrible pour un blocage complet du système, le noyau hurlerait sûrement sur son port série virtuel. Bingo, Yahtzee et huzzah !
[ 1203.905090] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 1203.912275] #PF: supervisor read access in kernel mode
[ 1203.917588] #PF: error_code(0x0000) - not-present page
[ 1203.922881] PGD 8000000124e2d067 P4D 8000000124e2d067 PUD 138d5e067 PMD 0
[ 1203.929939] Oops: 0000 [#1] SMP PTI
...blah...blah...blah
[ 1204.052766] Call Trace:
[ 1204.055440] bfq_idle_extract+0x52/0xb0
[ 1204.059468] bfq_put_idle_entity+0x12/0x60
[ 1204.063722] bfq_bfqq_served+0xb0/0x190
[ 1204.067718] bfq_dispatch_request+0x2c2/0x1070
Eh bien, bonjour, mon vieil ami ! C'était en effet un jour très chanceux !
C'était une panique du noyau que j'avais vue un an plus tôt et que j'avais travaillé sans relâche pendant des mois avec l'ingénierie du noyau en amont pour y remédier. Il s'agissait d'un bogue dans le sous-système de stockage du noyau chargé d'améliorer l'efficacité et de garantir que les précieux 0 et 1 sont écrits sur le disque. Dans ce cas, plutôt que de corrompre le stockage, le noyau a lancé un drapeau blanc et a tout stoppé net.
Ayant travaillé à peu près sur ce même problème auparavant, j'étais déjà au courant de la solution de contournement en une ligne. Il n'était plus nécessaire de traîner mon équipe pendant des mois de débogage. Je pourrais simplement signaler la récurrence et déployer en toute confiance la solution de contournement, sachant qu'elle résoudrait le problème à 100 % :
echo mq-deadline > /sys/block/sda/queue/scheduler
Maintenant, je ne recommande pas d'exécuter cette commande bon gré mal gré sur chaque système Linux que vous possédez. Dans ce cas précis, je savais par expérience passée qu'il était tout à fait sûr d'échanger l'algorithme de mise en mémoire tampon (également appelé ascenseur d'E/S). Aucun développeur de Podman ne remarquerait même le changement dans les résultats des tests.
[ Vous débutez avec les conteneurs ? Découvrez ce cours gratuit. Déploiement d'applications conteneurisées :présentation technique. ]
Récapitulez
Si vous ou quelqu'un que vous aimez rencontrez un jour une panique du noyau, je vous recommande de consulter cet article récent sur le sujet. Sinon, le principal point à retenir est le suivant :lors du dépannage à l'aveugle, il est absolument vital de résoudre les problèmes d'obscurcissement des causes. Deuxièmement, il faut travailler avec les données pour rendre le problème plus reproductible. Vous aurez beaucoup de mal à faire ce dernier sans l'aide du premier.