Chez Thirdbridge, nous sommes convaincus que les équipes orientées projet livrent des résultats de qualité supérieure, et ce, plus rapidement. Étant donné qu’elles sont responsables de l’intégralité du flux de création de valeur, ces équipes peuvent augmenter leur vélocité en éliminant elles-mêmes les goulots d’étranglement. De plus, accorder la responsabilité du flux de bout en bout à nos équipes de développeurs rend leur travail encore plus engageant et motivant.
Cependant, en pratique, nous avons rencontré certaines difficultés en tentant de démanteler les différents silos présents au sein de l’organisation. Sans grande surprise, le défi majeur a été de rendre les équipes autonomes par rapport à leur infrastructure, notamment celles qui doivent gérer un cluster Kubernetes.
Un peu d’histoire
Il y a fort longtemps, lorsque Thirdbridge n’était constitué que de quelques programmeurs fraîchement sortis des bancs d’école, nos infrastructures étaient comiquement mauvaises. Tous nos projets étaient hébergés sur le même serveur. Les déploiements étaient effectués manuellement en se connectant via SSH, en synchronisant l’historique git, puis en relançant le processus.
Très rapidement, nous avons réalisé que si nous voulions faire croître la compagnie, nous allions devoir être plus sérieux en matière d’infrastructure. En fonction des différents défis auxquels nous faisions face à l’époque, nous avons commencé à chercher une technologie qui pourrait nous aider à passer au niveau supérieur.
- Mise à l’échelle horizontale automatique: Certains de nos clients connaissaient une charge de trafic très variable, et nous cherchions une solution élastique pour mettre nos systèmes à l’échelle automatiquement.
- Mise à l’échelle horizontale manuelle: La mise à l’échelle automatique fonctionne bien dans la majorité des cas lorsque l’augmentation du trafic est constante. Cependant, certains de nos clients menaient d’importantes campagnes publicitaires avec des notifications mobiles, causant des pics de trafic quasi instantanés. Pour ces scénarios, la technologie choisie devait nous permettre de mettre manuellement le système à l’échelle en préparation de ces événements.
- Déploiement progressif : Arrêter et redémarrer manuellement les systèmes causait toujours une petite interruption des services. Pour les petits projets, ces interruptions n’étaient pas vraiment problématiques. En revanche, pour nos plus gros clients, nous voulions une technologie qui nous permettrait de déployer les nouvelles versions sans aucune interruption.
- Déploiement continu : Déployer manuellement les nouvelles versions n’était pas une approche extensible. Nous cherchions une solution automatisable avec quelques lignes de configuration dans notre pipeline GitLab.
- Système autonome : Nous étions encore traumatisés par un bug qui avait causé une boucle infinie dans l’un de nos systèmes. Comme le projet était en JavaScript (un seul thread), la boucle infinie avait paralysé tout le projet pendant quelques heures. Nous cherchions donc une technologie qui pourrait continuellement prendre le pouls de nos différents processus et les redémarrer en cas de problème majeur.
- Support de Docker: Nous commencions à prendre conscience de l’ampleur du potentiel associé à la conteneurisation et cherchions une solution compatible avec Docker.
Après avoir étudié les technologies existantes à l’époque, notre choix s’est arrêté sur Kubernetes.
Retour au présent
Plusieurs années se sont écoulées depuis que nous avons fait ce choix. De manière générale, nous considérons que ce fut une très bonne décision! Kubernetes nous a permis de résoudre tous les défis techniques que nous avons rencontrés et nous sommes conscients que nous n’avons fait qu’effleurer la surface des fonctionnalités offertes par cet outil.
Cependant, comme l’a dit oncle Ben à Peter Parker lors d’une profonde discussion sur les systèmes élastiques : Avec de grands pouvoirs vient une grande complexité.
Maintenant que Thirdbridge approche les 50 employés, la compagnie est divisée en plusieurs équipes, chacune responsable d’un ou plusieurs projets. Comme mentionné initialement, nous voulons que ces équipes soient le plus autonomes possible et que les développeurs soient responsabilisés au maximum.
Avec le temps, nous avons réalisé que la courbe d’apprentissage abrupte de Kubernetes rendait difficile l’adoption de cette technologie au sein de plusieurs équipes. Le résultat était prévisible et décevant. Les quelques personnes possédant une expertise avancée en Kubernetes devenaient rapidement des goulots d’étranglement. Les équipes n’avaient pas la confiance nécessaire pour innover et améliorer leur infrastructure.
Confrontés à cette situation, nous avons pris la décision de donner une chance à AWS ECS. Ce ne fut pas une décision évidente, mais plutôt le résultat de plusieurs compromis.
Simplicité vs fonctionnalité
Un compromis courant dans l’univers du développement web (et probablement dans plusieurs autres domaines) est la réduction de l’étendue des fonctionnalités en échange d’une meilleure expérience.
Par exemple, Vercel offre une meilleure expérience aux développeurs que AWS pour déployer certains frameworks web modernes comme NextJS ou SvelteKit. Le même paradigme s’applique pour les fonctions serverless en JavaScript. En acceptant quelques contraintes initiales, les Cloudflare Workers offrent une meilleure expérience et une tarification plus avantageuse que AWS Lambda.
La première question à laquelle nous devions répondre était de savoir si les fonctionnalités offertes par ECS couvraient les besoins énumérés plus haut, ainsi que de nouveaux besoins que nous avions ajoutés au fil du temps (e.g. une observabilité avancée, le support de CloudFormation, la résolution DNS privée, etc.)
La réponse fut positive. Nous avons été en mesure de reproduire la majorité des fonctionnalités présentes dans nos clusters Kubernetes existants.
La réduction de la complexité fut significative!
Plus besoin de rouler un DaemonSet Fluent pour la journalisation, nous pouvons désormais simplement utiliser Firelens.
Plus besoin de mettre en place un Horizontal Pod Autoscaler, un Metric Server et un Cluster Autoscaler, nous pouvons simplement utiliser des alarmes CloudWatch pour mettre en place une mise à l’échelle horizontale automatique.
Cela étant dit, nous ne sommes pas naïfs. Nous sommes conscients que Kubernetes offre plus de fonctionnalités que ECS. Cependant, pour nos cas d’utilisation, ces fonctionnalités supplémentaires sont inutiles et introduisent trop de complexité.
Dépendance AWS
La seconde crainte que nous avions concernait le vendor lock-in.
Kubernetes est pris en charge par la majorité des grands acteurs du cloud et est également disponible à travers plusieurs produits open source comme k3s. À l’inverse, ECS est une technologie fermée et propriétaire appartenant à AWS. Mais pire encore, le fait que ECS soit une technologie propriétaire n’est que la pointe de l’iceberg du verrouillage fournisseur.
La partie plus subtile est qu’ECS utilise plusieurs autres services AWS pour fonctionner. Par exemple, AWS Secret Manager pour la gestion des secrets, AWS Cloud Map pour la résolution DNS interne, ou encore AWS EventBridge pour la création de tâches périodiques.
Même pour un système avec un niveau de complexité relativement bas, une demi-douzaine de services AWS peuvent être nécessaires pour répliquer certaines fonctionnalités de base de Kubernetes.
Par contre, une fois cette réalité acceptée, il y a certains bénéfices. Chez Thirdbridge, nous sommes de grands adeptes d’infrastructure as code. Mes collègues et moi croyons que chaque projet sérieux devrait utiliser cette approche pour définir son infrastructure.
Une difficulté que nous avions avec Kubernetes est qu’il faut connaître deux syntaxes pour définir un système. Tous les composants reliés à Kubernetes (e.g. Deployments, Cronjob, DaemonSet, etc.) sont rédigés dans des fichiers de définitions Kubernetes alors que les autres ressources (CloudFront CDN, enregistrement Route 53, bucket S3) sont définies dans des fichiers CloudFormation.
En migrant vers ECS, nous pouvons définir nos infrastructures en utilisant exclusivement CloudFormation. C’est un petit détail, mais il simplifie grandement les choses. Nous espérons qu’en abaissant ainsi la barrière de complexité, les développeurs juniors pourront plus facilement se familiariser avec l’infrastructure as code.
Adoption serverless
Même si Fargate est aussi disponible pour EKS, nous n’avons jamais utilisé cette approche. Notre raisonnement était que faire fonctionner les Pods administratifs (e.g. CoreDns, CertManager, etc) dans un conteneur dédié Fargate était superflu. Comme ces Pods ne consomment habituellement pas beaucoup de ressources, il est logique de les faire cohabiter sur une même instance EC2.
Maintenant que nous avons migré vers ECS, l’utilisation de Fargate est plus naturelle. Ne plus avoir à gérer d’instance EC2 moyennant un coût supplémentaire nous semble un bon compromis. Il est vrai que la majorité du temps, aucune interaction n’était requise avec les instances EC2, mais quand un problème survenait, il était habituellement complexe et ardu à régler.
De plus, même si nous utilisons maintenant les fonctions Lambda de manière régulière pour certains types de tâches, nous pensons qu’un long-running process a des avantages importants pour des API Rest plus classiques où la majorité du temps d’exécution est liée au I/O de toute manière.
Pour l’instant, nous considérons donc que Fargate est l’abstraction serverless qui a le plus de sens pour plusieurs de nos systèmes.
Pour conclure…
En toute transparence, ce changement me chagrine un peu.
J’aime Kubernetes et j’ai investi une quantité de temps considérable dans l’apprentissage de cette technologie. Cependant, mes sentiments ne sont pas pertinents pour le bon fonctionnement de Thirdbridge.
Ce qui est important, c’est de mettre en place les fondations pour construire des solutions logicielles de qualité supérieure.
Nous pensons qu’en réduisant la complexité de l’infrastructure tout en offrant une vaste gamme de fonctionnalités, ECS permettra aux équipes de s’approprier plus facilement les infrastructures de leurs projets, favorisant ainsi l’innovation et augmentant la vélocité.
Donc pour l’instant, ECS sera notre technologie par défaut pour nos infrastructures. Nous sommes malgré tout conscients des limitations et des compromis liés à ce choix.
Nous suivrons aussi de manière attentive les avancements des Cloudflare Workers. Leur modèle d’exécution et de tarification étant plus adapté aux API Rest classiques que AWS Lambda. Maintenant que leur environnement d’exécution JavaScript se rapproche de la parité avec Node.js, cette technologie pourrait être un choix intéressant dans le futur!