J'ai récemment assisté à une présentation sur les outils et techniques de gestion de configuration, qui m'a inspiré une réflexion qui mérite qu'on s'y attarde.
Tout le monde s'accorde sur le fait que les outils d'infrastructure-as-code dédiés à la gestion de configuration sont essentiels et précieux, mais en parallèle, leur utilisation reste source d'une frustration relativement élevée. Et si les mécanismes existants de gestion de configuration ou d'infrastructure-as-code n'étaient plus une catastrophe ambulante ni un calvaire au quotidien ? À quoi cela ressemblerait-il ?

Une carte n'est pas le territoire — pourtant, on confond souvent les deux
Cet article explore comment le DevOps et le développement logiciel en général peuvent tirer profit d'une nouvelle façon d'envisager le provisioning et la configuration des systèmes, en revisitant la terminologie courante sous un angle nouveau.
Commençons par quelques définitions qui nous aideront à mieux saisir le monde qui nous entoure et à aborder les problèmes que beaucoup rencontrent.
La terminologie expliquée
Operations : la pratique consistant à veiller à ce que les systèmes logiciels fonctionnent correctement et répondent aux besoins des utilisateurs. L'operations engineer se préoccupe généralement moins de l'écriture de nouveau code ; il se concentre principalement sur le comportement d'un logiciel existant au sein d'un système existant.
Une fois ces deux termes posés, nous pouvons à présent expliquer en quoi le forward engineering diffère du reverse engineering.
Forward engineering
Le forward engineering consiste à construire un système à partir d'un modèle de ce qui devrait y exister. En FE, on crée d'abord le modèle, puis on déploie et configure ce template en production. L'attente est que le système réellement obtenu corresponde de près au modèle.
Bien souvent, le modèle déclaré est ambigu, et le système peut se comporter de manière inattendue, à rebours de l'intention initiale. C'est là un obstacle de taille à l'adoption de telles techniques, en particulier pour les nouveaux venus.
Pour ne rien arranger, le système lui-même finit souvent par diverger du modèle du fait de ses interactions avec son environnement, par exemple lorsque plusieurs composants modifient mutuellement leur configuration. Ou lorsque des procédures ad-hoc menées par les ingénieurs font évoluer le système dans des directions diverses.
En forward engineering, il n'existe aucune notion fondamentale de feedback vers le modèle initial. Le modèle est d'abord gravé dans le marbre, puis déployé. Tout retour ultérieur du système sur son comportement pourra être exploité pour faire évoluer les modèles et déploiements à venir.
Reverse engineering
Le reverse engineering consiste à élaborer un modèle partiel à partir d'un système existant et à s'en servir comme base pour le modifier. Il n'y a pas de modèle initial : c'est l'état actuel du système qui permet de découvrir comment les choses devraient fonctionner.
Dans bien des cas, les modifications apportées à un tel système se font de manière ad-hoc, directement sur le système, souvent sans en avoir une vision d'ensemble. Ici, le feedback est immédiat, et l'exploration consiste essentiellement à solliciter le système et à observer les retours qu'il produit.
Où retrouve-t-on le reverse engineering ? Vous avez sans doute entendu dire que les experts en sécurité s'appuient sur des pratiques de RE pour fouiller des logiciels existants à la recherche de failles. Ils analysent par exemple les services réseau ou la mémoire pour détecter des comportements anormaux et les exploiter en faisant agir le système d'une manière qui n'était pas prévue.
Le reverse engineering revient à observer un système ou un logiciel existant et, à partir de ce qu'il fait dans la pratique, à essayer de comprendre où se situent les écarts par rapport à l'intention initiale.
Où retrouve-t-on ces idées dans le monde du DevOps ?
L'infrastructure-as-code
Depuis la sortie de la première version de CFEngine en 1993, l'idée de modéliser l'infrastructure-as-code a connu une popularité fulgurante dans le secteur de l'ingénierie logicielle. On a commencé par déclarer le contenu d'un système d'exploitation serveur, avant d'adapter rapidement la démarche pour décrire la structure et la configuration des ressources cloud actuelles. Au fil des années, des entreprises et des outils ont eu leur heure de gloire, à l'image de Puppet, Chef, Salt, Ansible, CloudFormation, Terraform, CDK, Pulumi et de nombreuses autres solutions maison.
Le point commun à la plupart de ces outils, c'est qu'ils sont déclaratifs. Les outils déclaratifs nous permettent uniquement de spécifier comment les choses devraient être, sans expliciter les étapes pour y parvenir. Ces dernières années, plusieurs outils ont émergé en revendiquant une approche plus impérative. Pourtant, ils restent fondamentalement déclaratifs et se distinguent des langages traditionnels de développement logiciel impératif utilisés pour écrire du code.
Pourquoi la plupart de ces outils sont-ils déclaratifs ?
Pour faire simple, parce que c'est la façon la plus aisée de créer des cartes, des modèles et des templates. Un ingénieur n'a qu'à déclarer comment les choses doivent être et où chaque élément doit se trouver, puis à déléguer le travail laborieux qui consiste à mettre chaque élément à la bonne place et sous la bonne forme. Cela permet une amélioration itérative dans la durée, qui mène à terme à des systèmes plus robustes et plus stables.
Autre avantage commun aux outils déclaratifs d'infrastructure-as-code : la propriété d'idempotence. L'idempotence signifie que répéter une action plusieurs fois produit un résultat constant. Lorsqu'on utilise un outil idempotent pour modifier un système à plusieurs reprises, ce dernier finit par atteindre l'état déclaré par le template. Réappliquer ensuite le même template n'aura plus aucun effet sur le système. C'est cette propriété qui nous permet d'appliquer le modèle plusieurs fois et de ne modifier le système que lorsqu'il s'écarte du modèle.
Une approche impérative exigerait d'identifier d'abord toutes les différences entre le modèle et le système, puis de mettre en œuvre chaque étape requise pour chaque changement. Les outils déclaratifs d'infrastructure-as-code y parviennent sans que le développeur ait à écrire toutes les actions lui-même.
Les outils d'infrastructure-as-code sont populaires et essentiels : ils font économiser des milliers d'heures de travail en produisant des templates réutilisables et en permettant de répliquer des systèmes quasi identiques sur différents environnements avec un effort marginal minimal.
L'infrastructure-as-code promet qu'une amélioration itérative du modèle dans la durée mène à des systèmes robustes et stables fondés sur ce modèle.
Un de mes précédents articles sur la configuration de plusieurs systèmes explique en quoi des répliques de systèmes quasi identiques sont bénéfiques pour les éditeurs de logiciels.
Mais ! Ces outils relèvent d'une logique de forward engineering : ils sont déclaratifs et n'offrent aucun mécanisme pour recueillir les retours d'un système en production. Cette approche a engendré au fil des années nombre de problèmes et de plaintes de la part de ses utilisateurs, que nous pouvons explorer.
Les limites de l'infra-as-code en forward-only engineering
Avez-vous déjà entendu le terme Configuration Drift ? Il survient lorsque le modèle déclaré ne correspond plus à l'état du système. Tout système, après suffisamment de mises à jour, finira presque toujours par diverger du modèle ayant servi à le créer.
Le drift peut apparaître lorsqu'un développeur modifie le code du modèle sans mettre à jour tous les systèmes qui en sont issus, ou lorsqu'un ingénieur mène des opérations exploratoires ad-hoc et modifie un système sans revenir au template pour en mettre le code à jour. Ces deux activités sont essentielles : les développeurs s'adonnent à la première pour intégrer des améliorations dans les prochaines itérations de déploiements, et les operations engineers s'adonnent souvent à la seconde pour découvrir et résoudre des problèmes inconnus.
Le configuration drift est bien entendu un piège classique qui ne demande qu'à se déclencher, raison pour laquelle tout le monde répète qu'il faut l'éviter. Mais est-il réaliste d'interdire aux opérateurs d'intervenir sur les systèmes pour proscrire toute exploration ad-hoc ? Oui. Certaines entreprises imposent qu'aucun opérateur ni développeur ne touche à un système en production. On imagine aisément ce qu'une telle politique fait au Mean-time-to-Recover de ces systèmes. D'expérience, dès que ça part en vrille et qu'un système de production lâche pour une raison ou une autre, c'est la première règle qui saute, et l'exploration ad-hoc est immédiatement autorisée à quiconque peut tirer les choses au clair.
Les ingénieurs séduits par l'infrastructure-as-code se plaignent souvent du travail considérable que représente la remodélisation d'un système existant en partant de zéro. Il se trouve toujours quelqu'un pour développer un outil censé y remédier. Google a GCP Terraformer, AWS a son AWS CloudFormer (abandonné), et même Azure a son ARM disséminé un peu partout dans sa console cloud. Il y aura toujours quelqu'un pour bâtir ce genre d'outil pour votre langage de gestion de configuration favori, parce que la demande est tout simplement énorme.
Malheureusement, une fois qu'un ingénieur a utilisé un tel outil, il en ressort généralement déçu. Le résultat est soit un bruit confus qui n'a aucun sens, soit, au mieux, déjà obsolète le lendemain. Le mieux que l'on puisse faire avec un template ainsi reverse-engineeré, c'est d'en copier-coller des extraits dans un template rédigé manuellement ailleurs.
Améliorer la voie à suivre
Cet article a posé deux définitions et expliqué en quoi le forward-only engineering est sous-optimal pour l'exploitation réelle des systèmes, et pourquoi, dans la plupart des cas, le reverse engineering reste indispensable pour identifier et résoudre les problèmes.
La proposition est donc de faire émerger une nouvelle génération d'outils d'Infrastructure-as-Code, des outils qui placent le reverse engineering au cœur de leur fonctionnement et permettent aux retours des systèmes en production de mettre à jour les modèles qui leur ont donné naissance. Un opérateur peut alors soit adopter la modification ad-hoc, soit la rejeter pour ramener le système à l'état déclaré dans le modèle d'origine.
Les outils standards du marché peinent à aider les ingénieurs à résoudre les problèmes qui surgissent lors de l'exploitation des systèmes. Oui, plusieurs outils permettent d'auditer vos templates Terraform et de vous signaler erreurs ou mauvaises configurations. Ces audits sont utiles, mais la vraie valeur de ce type d'aide réside dans l'inspection d'un système réellement en production, et pas seulement du template que les ingénieurs ont un jour utilisé pour le créer.
À ma connaissance, nous ne disposons pas d'un outil suffisamment abouti pour intégrer davantage de pratiques de reverse engineering dans le quotidien des operations engineers. Nous avons quantité d'outils de monitoring et d'observabilité d'un côté, et de nombreux outils d'infrastructure-as-code de l'autre, avec un fossé considérable au milieu.
Vous avez des idées pour combler ce fossé ? N'hésitez pas à nous en faire part !
Image de couverture créée par Tabea Schimpf sur Unsplash.