Tout le monde disait de passer au serverless. Nous avons gardé le cluster Kubernetes qui tourne à vide la plupart du temps
Le conseil est partout et il semble évidemment juste. Vous gérez l'authentification pour des tenants dont le trafic est en dents de scie. Vous payez un cluster Kubernetes vingt-quatre heures sur vingt-quatre. Azure Container Apps vous fait passer à zéro et ne vous facture que ce que vous consommez. Arrêtez de payer pour l'inactivité.
Nous l'avons pris au sérieux. Nous avons chiffré la migration vers Azure Container Apps, examiné de près ce qu'elle nous apporterait, et sommes restés sur AKS. Voici le raisonnement, car ce n'est pas celui que l'on devinerait à partir du graphique d'utilisation du cluster.
Le conseil est juste, pour une charge de travail que nous n'avons pas
Les conteneurs serverless conviennent parfaitement au traitement de requêtes sans état et par à-coups : chaque requête est indépendante, les instances sont du bétail, et zéro trafic devrait signifier zéro facture. Cela décrit bon nombre de backends web.
Cela ne décrit pas un backplane d'authentification. Le nôtre n'est pas inactif à la manière dont une application sans état est inactive. Il détient le leadership du cluster et fait tourner la couche de coordination qui décide quel réplica effectue le travail singleton, comme le balayage de rétention et la passe de webhooks. (Ce leader, nous l'élisons désormais via un bail de blob, et non plus par gossip, ce qui est une autre histoire.) Que le cluster soit tranquille ne veut pas dire qu'il n'a rien à faire ; cela veut dire qu'il se tient prêt à valider le prochain token et à continuer d'être le leader. Tranquille et inactif ne sont pas le même état.
Nous avons supprimé la facture d'inactivité sans déménager
Voici ce qui a tranché : le coût que nous cherchions à fuir avait un remède bien moins cher qu'une reconstruction de plateforme.
Ce qui vidait les caisses, c'étaient des nœuds tournant 24 h/24 alors que le trafic se concentrait sur les heures de travail. Nous avons donc fait en sorte que le cluster de dev se désalloue quand personne ne l'utilise (éteint la nuit et le week-end, relancé à la demande) et basculé le pool de nœuds vers une SKU moins chère. Cela a éliminé l'essentiel des dépenses d'inactivité que le serverless promettait de supprimer, et cela nous a coûté un changement de configuration plutôt qu'une migration. Quand les économies visées sont atteignables sur place, reconstruire la plateforme pour courir après le même chiffre représente beaucoup de risque pour un écart déjà capté.
La leçon se généralise : chiffrez le correctif avant de chiffrer la reconstruction. « Arrêter de payer pour l'inactivité » est un objectif, pas une architecture, et le moyen le moins cher d'y parvenir est souvent un planificateur et une SKU, pas un nouveau runtime.
Le scale-to-zero se bat contre un backplane qui doit tenir un bail
Même en mettant le coût de côté, le scale-to-zero est franchement inadapté à cette charge de travail, de deux manières.
Premièrement, les démarrages à froid tombent sur le pire chemin possible. La requête qui paie la taxe du démarrage à froid, c'est quelqu'un qui essaie de se connecter, et « votre connexion a été lente parce que notre service d'authentification dormait » n'est pas une phrase que l'on a envie de livrer.
Deuxièmement, le leadership et le scale-to-zero sont en conflit direct. On ne peut pas tenir un bail depuis une instance qui a été mise à l'échelle vers le néant. Un backplane dont tout le rôle est d'avoir toujours exactement un leader vivant ne veut pas d'un runtime dont tout le rôle est de retirer les instances quand elles paraissent tranquilles. Nous nous battrions contre le comportement fondamental de la plateforme pour préserver le nôtre.
Le runtime nous aurait retiré trois choses dont nous nous servons
Migrer n'est pas gratuit, même là où ça marche ; vous héritez du bac à sable du runtime managé, et le nôtre bloque des choses dont nous dépendons :
- Twingate. Nous atteignons les ressources privées via un connecteur Twingate. Le bac à sable des conteneurs managés ne l'exécutera pas, il nous faudrait donc réinventer un accès réseau privé que nous avons déjà.
- Notre chaîne de build. Des parties de notre pipeline s'appuient sur Docker-in-Docker et
az acr buildcontre un registre privé, deux choses que le bac à sable interdit. C'est tout un système de build à reconstruire, pas seulement une cible de déploiement à changer. - Le contrôle cross-cloud. Nous faisons tourner un standby AWS qui valide les tokens émis par le primaire Azure, via des JWKS fédérées, avec Cloudflare comme arbitre de bascule. Cela exige un contrôle du réseau et du placement qu'un runtime managé masque délibérément.
Chacune de ces choses est un contournement qu'il nous faudrait écrire juste pour revenir là où nous sommes déjà. Le véritable coût de la migration n'est pas le basculement ; c'est de regagner chaque capacité que le bac à sable retire.
L'économie a une traîne, et nous l'avons payée
Rester n'est pas non plus sans conséquences, et l'honnêteté impose de le dire. Désallouer les nœuds la nuit nous a valu une panne que nous n'aurions jamais vue sur un cluster toujours actif : une course sur le token du premier pull d'image sur les nœuds froids (celle de l'issue AKS 4052) qui bloquait parfois le démarrage d'un pod après le rallumage du cluster. Nous l'avons corrigée avec un délai de rollout plus long et, en production, en ne désallouant pas comme le fait le dev.
Voilà la vraie forme du compromis. Chaque chemin a sa traîne de modes de défaillance ; la question est de savoir si vous pouvez les voir et les corriger. Sur AKS, la course des nœuds froids était inspectable et réparable. Les genres de bizarreries dont on hérite des entrailles d'un runtime managé sont celles pour lesquelles on ouvre un ticket de support et on attend.
La règle que nous en avons tirée
Deux choses, réutilisables au-delà de nous. Ne migrez pas pour fuir un coût que vous pouvez tuer sur place ; chiffrez d'abord le correctif sur place, car un planificateur et une SKU moins chère battent une reconstruction de plateforme la plupart du temps. Et faites correspondre le runtime à la forme de la charge de travail : le serverless récompense le sans-état et l'à-coup et punit l'à-état et le toujours-actif, et un cœur d'authentification qui détient vos clés de signature et le leadership de votre cluster relève fermement de la seconde catégorie.
Nous ne sommes pas contre le serverless. Une bonne partie de notre surface sans état s'y porterait très bien. Mais la partie qui détient vos clés et décide qui exécute les tâches destructrices continuera de tourner sur une infrastructure ennuyeuse, toujours active et inspectable. Parfois, le cluster qui semble inactif est l'option bon marché, une fois comptabilisé tout ce qu'il faudrait reconstruire pour le quitter.
L'infrastructure toujours active et inspectable sous vos connexions est une fonctionnalité, pas un oubli. C'est exactement ce que vous déléguez lorsque vous confiez votre authentification à Authagonal au lieu d'exploiter le backplane vous-même.