
Dans les coulisses
IA et transparence des prix : projets et conclusions du Hackfest
par Martin Jungfer
Les déploiements d'aperçus sont toujours une chose, surtout si vous ne les nettoyez pas. Je vous explique ici ce que sont les déploiements d'aperçus et comment nous les avons mis en forme.
Celui qui s'occupe de déploiements sous une forme ou une autre sait qu'il faut de temps en temps les mettre à jour, et celui qui met à jour veut aussi pouvoir tester (et même celui qui ne veut pas doit quand même le faire, mais c'est un autre thème). En ce qui concerne le front-end, il y a une difficulté supplémentaire : il faut souvent tester plusieurs modifications différentes en même temps, c'est pourquoi nous ne pouvons pas simplement écraser le déploiement de test existant. C'est pourquoi il existe des déploiements d'aperçu. Il s'agit de déploiements frontaux destinés à tester une modification spécifique, et qui doivent parfois être exécutés en parallèle en grand nombre. Pour que les non-techniciens puissent les visualiser sans avoir à suivre un cours, ils doivent être facilement accessibles dans le navigateur.
Dans notre cas, tous ces déploiements fonctionnent sur Kubernetes, plus spécifiquement sur Azure Kubernetes Service (AKS), ce qui nous apporte quelques avantages, mais ne nous dispense pas de tout. Nous utilisons également GKE, alias Google Kubernetes Engine, mais pas pour ce cas d'utilisation. AKS ne fait pas non plus le ménage volontairement, ce qui ne pose pas de problème pour les déploiements réguliers (où les nouvelles versions écrasent les anciennes), mais pour les aperçus frontaux, qui ne peuvent justement pas s'écraser les uns les autres et sont donc parfois présents en nombre imprévisible, oui. Elles doivent être rangées correctement après utilisation. Mais nous ne voulions pas en entendre parler lorsque nous étions enfants, et comme les informaticiens ne sont en fait que des grands enfants de huit ans, il ne faut pas trop attendre de nous dans ce domaine. Nous avions donc beaucoup de déploiements en cours, et avec eux des types de ressources dédiés, Service et Ingress, et personne pour faire le ménage régulièrement. Pourrions-nous au moins garder les pods responsables de la consommation de CPU et de RAM à zéro jusqu'à ce qu'ils soient nécessaires?
Horizontal Pod Autoscaler à la rescousse ! Si seulement c'était aussi simple... parce qu'il ne s'adapte pas à zéro, ou plutôt il n'augmente pas un déploiement avec zéro réplicas, car il aurait besoin d'au moins un pod dont il peut mesurer la consommation de CPU et de RAM. Nous avons donc dû maintenir tous les déploiements de prévisualisation avec au moins un pod en fonctionnement, au cas où quelqu'un voudrait y jeter un coup d'œil - et nos équipes frontales déploient très activement. Cela coûte des ressources qui ne sont pas disponibles pour d'autres déploiements et qui doivent être compensées par des nœuds plus nombreux ou plus grands - mais ce n'est pas donné. Il fallait donc trouver une autre solution, et après quelques recherches, nous l'avons trouvée dans Knative.
Red Hat dit : kay-nay-tiv. Nous utilisons le composant Serving de celui-ci. Pour les événements, nous utilisons plutôt KEDA, mais c'est une autre histoire que nous raconterons une autre fois - nous n'utilisons pas non plus de fonctionnalités telles que le partage de trafic actuellement.
Les services Knative ressemblent à la triade habituelle déploiement-service-ingress, mais ils utilisent leurs propres définitions de ressources personnalisées et sont capables d'évoluer à partir de zéro dès que les requêtes arrivent. Cela nous permet de construire et de déployer un déploiement en avant-première à partir de toutes les demandes d'extraction, sans avoir à réserver de ressources système pour cela, que quelqu'un le regarde ou non. Un contrôleur d'ingress dédié, propre à Knative et appelé Kourier, permet également d'acheminer les requêtes vers l'instance souhaitée sans avoir besoin de régler quoi que ce soit manuellement.
Voici à quoi ressemble un déploiement régulier :
Et une autre, créée avec Knative :
Il va sans dire que nos équipes de fonctionnalités ne doivent pas avoir à s'occuper de Knative ou d'autres thèmes liés à l'infrastructure plus que nécessaire. Nous, Team Bender, sommes l'une des nombreuses équipes d'ingénierie de plateforme et, en plus de Kubernetes, nous sommes également responsables de rendre le déploiement aussi confortable que possible pour les feature teams. C'est pourquoi nous avons entrepris, il y a quelque temps déjà, de créer une collection de chartes de casques qui font abstraction de tous les mauvais détails, de sorte que chaque équipe n'a besoin que d'un simple fichier values.yaml avec les informations les plus importantes dans son référentiel.
La mise à disposition de Knative s'est essentiellement faite en deux temps :
Le contrôleur d'accès Kourier, en collaboration avec Wildcard-DNS, nous a ensuite aidés à mettre à disposition chaque déploiement d'aperçu sous son ID de requête d'extraction, et c'est parti.
Pas de problèmes, mais des défis. Kourier, en tant que contrôleur Ingress supplémentaire, nous a coûté un peu de travail supplémentaire. En principe, nous utilisons Nginx. Nous aurions préféré qu'il en soit de même pour Knative, car les règles Ingress doivent souvent être configurées spécifiquement pour le contrôleur. Comme nos déploiements en avant-première utilisent tous un sous-domaine joker qui n'est utilisé pour rien d'autre, nous avons pu facilement diriger le trafic vers Kourier sans que Nginx ne se sente concerné.
Malheureusement, les déploiements Knative ont des caractéristiques de performance légèrement différentes de celles des déploiements réguliers à certains endroits, ce qui limite notre capacité à les utiliser pour les tests de charge. Nous soupçonnons le contrôleur Kourier de mettre en mémoire tampon à certains endroits où Nginx ne le fait pas, mais nous ne pouvons pas faire plus que lire dans le marc de café à ce stade. Heureusement, le marc de café fait rarement défaut dans un département informatique.
Un autre défi était que Knative ne supporte pas les montages hostPath. Datadog, que nous utilisons comme solution de monitoring, en a besoin pour pouvoir monter sa config dans n'importe quel pod, et nous sommes donc pour l'instant sans métrique et sans alerte en ce qui concerne les déploiements en avant-première. Les déploiements réguliers n'utilisent pas Knative, ce n'est donc pas si grave, même s'il serait bon de pouvoir identifier les problèmes éventuels à ce stade. Les détails sont encore un peu nébuleux, mais nous avons déjà une idée de base de la façon dont cela pourrait être résolu.
Le plus grand défi a été le nettoyage mentionné ci-dessus. En effet, Knative ne le fait pas tout seul.
Knative crée plusieurs services pour chaque déploiement d'aperçu, afin que les anciennes et les nouvelles versions puissent coexister. Et comme nous n'avons pas tous la même motivation pour faire le ménage, des milliers de ressources K8s ont fini par traîner dans l'espace de noms frontal. Kubernetes n'apprécie pas beaucoup cela, car aucun service ne trouve plus ses pods dans cet espace de noms jusqu'à ce que vous invoquiez votre Marie Kondō intérieure et fassiez ce qui doit être fait. Nous nous en sommes aperçus parce que les déploiements frontaux de test réguliers, avec lesquels Knative partage le même espace de noms, ne fonctionnaient plus non plus - ce n'est pas la meilleure idée, comme nous l'avons constaté. De toute évidence, le simple fait de maintenir le nombre de pods à zéro n'était pas suffisant.
Nous avons donc construit des scripts shell (un peu vieux, mais toujours utiles) qui sont exécutés par des pipelines réguliers et qui suppriment automatiquement tous les déploiements de prévisualisation de plus de 14 jours, ainsi que tous ceux dont les requêtes d'extraction ont été complétées. Ainsi, nos espaces de noms sont toujours propres et Kubernetes n'a plus de mal à faire son travail.
Un rapide coup d'oeil dans l'espace de nommage (avec l'aide généreuse de kubectl et grep) montre qu'il y a actuellement (au 01/06/2023, 12h52) 43 déploiements de prévisualisation. Les pods de prévisualisation sont au nombre de trois. Donc, 40 déploiements fonctionnent actuellement avec zéro pod, alors qu'il y en avait au moins un avant Knative. La plupart des nœuds de notre cluster d'essai disposent de 16 cœurs de processeur et de 32 Go de RAM - tous ces pods de prévisualisation qui ne fonctionnent pas parce que nous n'en avons pas besoin nous font économiser environ un demi-nœud. Dans la pratique, il s'agit plutôt d'un nœud entier. Cela n'a l'air de rien, mais c'est une économie sensible pour nous et ce n'est probablement que la partie émergée de l'iceberg : tous les pods qui auraient fait partie des déploiements de previews que nous ne voyons plus parce que nous les nettoyons régulièrement, leur nombre a dû être bien plus élevé encore.
À titre d'illustration, voici deux graphiques révélateurs qui montrent clairement nos économies en fonction du nombre de pods au fil du temps :
Je sais qu'il n'y a pas beaucoup de détails, mais j'ai quand même étiqueté les axes.
Bien sûr, nous sommes loin d'avoir terminé la mise en œuvre de Knative. Certains des défis mentionnés sont encore à relever, d'autres pourraient être plus performants, et qui sait si nous ne trouverons pas demain une meilleure alternative à Knative.
Avez-vous déjà eu affaire à des cas d'utilisation similaires ? Comment avez-vous résolu le problème, en utilisant Knative ou autre chose ? Idées, remarques, questions, numéros de la loterie de demain, n'hésitez pas à les partager dans les commentaires !