infrastructure immuable, c'est quoi ça ?
On commence à entendre pas mal parler de ce concept de l’infrastructure immuable (immutable infrastructure), mais c’est quoi ce délire encore et surtout faut-il regarder de plus près ?
Principe
Le principe de base derrière le concept de l’infrastructure immuable repose sur le fait qu’une fois déployée, l’infrastructure en place pour une application ou un composant de l’application restera inchangée dans le temps. Les évolutions et les corrections seront apportés à chaque fois sur une nouvelle version. On oublie donc le principe bien connu d’effectuer des modifications au fil de l’eau sur le paramétrage de l’OS, des middlewares ou des outils installés afin de corriger des dysfonctionnements ou d’améliorer la sécurité.
Ce principe s’applique assez bien à la partie “compute” et beaucoup moins aux parties relatives aux infrastructures comme le réseau, le stockage ou la sécurité sauf à disposer d’une infrastructure totalement pilotable via des API (Software Defined). On positionne donc bien ce concept dans le cadre des applications et idéalement sur des infrastructures de type cloud que celui-ci soit interne ou posé chez un des acteurs du marché.
Afin de se projeter facilement dans ce mode de fonctionnement, il est impératif de s’être déjà mis dans une posture d’infrastructure as code, car remonter un socle complet s’il y a des opérations à réaliser à la main sera fastidieux et surtout source d’erreur. Tout doit être effectué à partir de votre outillage de provisionning, aucune action manuelle ne doit être nécessaire à part le lancement de l’opération. Si vous ne vous fixez pas cet objectif, l’approche sera contre productive et surtout vous ne bénéficierez pas des avantages de la solution.
Il est évident avec ces simples principes que le mode de fonctionnement connu depuis des décennies qui consiste à dissocier fortement l’infrastructure technique des applications qu’elle sous-tend est en opposition. Mais en prenant un peu de recul, monter la version de son système d’exploitation ou des composants de sécurité de son middleware est assez complexe. Cela impose des tests de non régression qui peuvent ne pas être automatisés (voir totalement manuels), or nous savons tous que ces actions sont longues, pénibles et souvent ralentissent les mises en œuvre qui dans le cas présent n’apportent souvent rien au métier.
Pourquoi ?
Mais alors pourquoi se casser à la tête à faire autrement ? On peut tout à fait conserver une séparation forte entre l’infrastructure et le développement, les métiers sont différents et les responsabilités dans les DSI sont souvent différentes également. Ceux qui montent les socles sont souvent ceux qui sont responsables du bon fonctionnement in-fine du système d’information et par conséquent prennent des précautions vis-à-vis de ces phases de mise en production et de contrôle des composants.
Mon propos n’est pas de réunir l’ensemble de ces compétences très différentes sous une seule bannière ou de chercher des compétences capables d’embrasser à la fois le code et l’infrastructure. On doit bien faire des actions sur les deux types de sujets et chacun va apporter sa vision et ses compétences.
Immutable infrastructure c’est bien d’abord de l’infrastructure. Certes elle est au service de l’application qu’elle sous-tend mais pas plus qu’avant lorsque l’on se permettait de modifier les systèmes une fois constitués pour en assurer le maintien en condition opérationnelle.
L’apport principal de cette solution est bien de gagner du temps et de la qualité sur l’infrastructure.
Les avantages directs à l’approche immutable infrastructure sont :
- reproductibilité des constructions : deux exécutions successives de mise en œuvre du même socle reconstruira la même infrastructure (en tout cas c’est bien l’objectif), ceci est sécurisant pour tout le monde, les équipes opérationnelles d’infrastructure aussi bien que les équipes études qui attendent un certain confort dans leur environnements de travail depuis le build jusqu’au run
- gestion du cycle de vie de l’infrastructure : puisque l’on décrit l’infrastructure plutôt qu’on ne la construit, il est beaucoup plus simple de se projeter dans un plan de version, un travail itératif sur une méthodologie agile, des engagements de livraison
- capacité à gérer un nombre élevé d’environnement : puisque l’on dispose de la reproductibilité des constructions, il est alors évident que l’on peut instancier autant d’environnements en parallèle qu’on le souhaite pour les différents besoin des équipes projets, on pourra même garantir l’utilisation de version spécifique sur chaque environnement
- simplicité de montée de version : il est souvent indispensable de monter de version, que ce soit au niveau du socle ou de l’application. Avec cette approche, la nouvelle version sera montée en parallèle de la première et le passage de l’un à l’autre déjà près techniquement
- responsabilisation sur le socle : c’est qui le patron ? le responsable des infrastructure avec son plan de version, la reproductibilité et la capacité à simplement appliquer une nouvelle version ou environnement sera réellement considéré comme maîtrisant son sujet, ce qui n’est pas toujours le cas aujourd’hui
- capacité à opérer : le travail d’ingénierie est important pour la constitution du socle initial, mais représente plus un cumul de compétences. Une fois constitué, le travail sera principalement itératif, simple à tester (test and learn), trivial à exécuter.
Gestion d’image et de modèle
Tous les systèmes ne sont pas simples à installer, certaines applications nécessitent beaucoup d’adaptations manuelles suite à la mise en place du système d’exploitation. Il est donc important de mettre en place très tôt dans sa réflexion d’infrastructure as code d’un outillage et d’une méthodologie permettant de construire, de patcher simplement, d’installer les différents composants qui vont constituer les images nécessaires à la mise en place de son infrastructure applicative.
Afin d’aller vite, il faut utiliser autant que possible les systèmes d’installation à base de script. Que ce soit via un développement maison, du paramétrage via ansible/chef/puppet ou tout autre système, il faut viser le fait que le résultat soit reproductible : deux instanciations à une semaine d’intervalle doivent fournir le même résultat sur la base de la même description. Ceci doit être vrai même si les composants ont changé de version entre deux itérations. Il sera donc peut-être nécessaire de se constituer un référentiel des composants (internes et externes) et de nommer lesquels sont utilisés dans les descriptions et les scripts afin qu’il n’y ait pas d’équivoque.
Une fois ces outils maîtrisés, vous constaterez vite qu’ils pêchent par leur lenteur d’exécution. Effectivement, remonter un système et son paramétrage à partir de l’image ISO de l’OS en provenance directement de la distribution éditeur est long. Ceci est d’autant plus vrai que l’on a beaucoup de serveur ou d’instance à construire et que les composants à installer et paramétrer sont nombreux.
L’étape suivante nécessitera d’adapter votre processus de construction de socle à votre système d’hébergement. Dans le cloud, il y a toujours un système d’image “maison” (ie AMI chez AWS) qui permet de repartir rapidement d’un point un peu plus avancé, si votre hébergeur ne vous propose pas cela, changez-en !
Ceci est également vrai pour les images applicatives, on pourra utiliser des outils de packaging comme rpm ou apt par exemple sur Linux et bien sûr les conteneurs (lxc ou docker). A regarder donc les systèmes de gestion des artefacts : jfrog artifactory, sonatype nexus ou encore pulp.
Gestion du cycle de vie
Lorsque l’on travaille sur ce type de système d’automatisation des constructions de socle technique, il est important de voir l’ensemble des étapes du cycle de vie : la construction, la modification, la destruction, l’audit.
Vous devrez donc veiller à regarder comment se comporte votre système à chaque étape, en commençant par le fait que les constructions soient effectives, documentées, versionnées afin de garantir la traçabilité dont vous avez besoin en premier lieu sur la phase de construction.
La destruction doit être totale. Pas question d’oublier un composant d’infrastructure, un paramétrage et qu’il soit donc nécessaire de faire des opérations manuellement afin de finaliser la destruction. La qualité de cette phase permettra de garantir une maîtrise des coûts sur les environnements cloud avec un paiement à l’acte ou au temps.
La modification consiste plutôt dans le cadre des infrastructures immuables à la mise en place d’une version modifiée (correctif, évolutif) : comment garantir que je peux passer à une nouvelle infrastructure sans impact pour mes équipes étude et développement, test, production. Ceci embarque les notions de nommage, de référentiel, de dictionnaire, il faudra donc jouer avec le DNS, les systèmes clé/valeur, le LDAP, …
L’audit est une partie importante des travaux de préparation car elle va vous permettre après coup de valider ce qui a été fait, de le reprendre, de démontrer la qualité ou la validité. Je préconise sur ce sujet d’utiliser un autre système que celui qui a permis de monter l’infrastructure, à la manière des tests que l’on embarque dans son code, de façon a disposer d’un biais différent. On pourra par exemple se baser sur les API des différents éditeurs, les outils d’analyse d’OS, de sécurité et de packaging afin de valider que l’inventaire en fonctionnement est bien celui qui était décrit initialement et qu’il n’a pas été altéré. C’est probablement le point le plus complexe et le plus chronophage de la gestion du cycle de vie, à vous de voir s’il faut le démarrer dès le début ou faire pendant un premier temps quelques opérations manuellement.
Canary deployment
Vous disposez déjà d’une version de votre application et de son socle technique, tout est parfait et fourni le bon niveau de service, mais vous souhaitez mettre en production les évolutions et les correctifs de la nouvelle version que le métier et les clients attendent impatiemment.
Deux cas d’école principaux, une approche standard ou du déploiement progressif.
Dans le premier cas, vous établissez la liste des changements nécessaires, préparez une livraison technique et applicative et les packages nécessaires, votre équipe de production répète sur un environnement de pré-production ou d’homologation l’ensemble des procédures, on refait un tour de clé avec quelques tests voir une recette complète et on refait de même sur la production. Normalement les premières occurrences se passent assez bien, mais au fil du temps, des livraisons et des correctifs en cours de route les environnements se désynchronisent, la documentation n’est pas forcément tenue, les personnes changent et on fini par ne plus maîtriser l’environnement et avoir des comportements difficiles à reproduire.
Le cas du *canary deployment ou blue/green deployment est plus engagé, puisque il nécessite que vous construisiez un nouveau couloir complet pour votre production (bleu) et basculiez progressivement le trafic de vos utilisateurs vers le nouveau couloir afin de valider le comportement. Une fois la totalité du trafic utilisateur migré sur le nouveau couloir, l’ancien (vert) est tout simplement détruit.
Vous arriverez assez vite à la conclusion que la seconde solution est beaucoup plus intéressante en termes de stabilité mais nécessite de reconstruire la totalité ce qui nécessite un travail amont très différent. Il faut effectivement être en mesure de construire de façon totalement industrielle l’environnement depuis l’OS jusqu’aux composants applicatifs et peut-être même aux données.
C’est néanmoins une bonne cible pour la majorité des applications développées de nos jours et prend une dimension totalement différente dans les approches de développement agiles avec des mises en production assez fréquentes (jusqu’à quotidiennes).
Les solutions techniques sont néanmoins généralement bien connues pour arriver à ce type de déploiement progressif, souvent à base de DNS et de load-balancer, des composants que vous avez probablement déjà en place sur votre infrastructure, donc pas de panique.
Le paramétrage externalisé
Coder sans penser à sortir des paramètres est une folie, il vaut mieux en mettre trop que pas assez. Ceci est indispensable sur la partie relative à l’environnement. Si vous souhaitez pouvoir instancier plusieurs fois votre application dans différents environnements ou pour différents usages ou clients, il est alors indispensable d’externaliser le plus possible de paramètres (exposition du service via le réseau, accès base de données, url d’accès, thème à utiliser, adresse de courriel, utilisateurs et droits, …).
Souvent on utilisera un fichier pour stocker tout cela, dans certains cas quelques valeurs seront changées par des variables d’environnement positionnées à l’exécution du programme. On trouve de plus en plus de solutions dynamiques basées sur des systèmes de découverte de service ou de système clé/valeur. Ceci permet notamment d’apporter de la dynamique et surtout d’éviter de manipuler plusieurs fichiers pour une solution composée de plusieurs applications.
Il est indispensable de prendre un peu de temps pour monter ce type de solution via un etcd, un redis ou un consul par exemple. Cette solution permettra à plusieurs équipes de centraliser leurs variables, de gérer une multitude d’environnement, de faire du RBAC et d’étendre l’usage à bien plus de paramétrage fonctionnels dans l’application que les simples paramètres d’environnement.
Par où démarrer ?
C’est bien beau tout cela, mais comment on démarre sa réflexion alors que ses équipes de développement et de production sont à la manœuvre en permanence pour faire avancer l’infrastructure, les middleware et le code pour ses clients ?
Les travaux à mener doivent se porter sur les sujets suivants :
- socle système propre pour les serveurs, peut importe l’OS, il faut savoir comment l’installer, mettre les composants indispensables, supprimer les superflus
- les moyens de gérer l’administration, la supervision, le contrôle du système : les logs, le SNMP, le NTP, le mail, la sécurité, l’IAM, …
- les middleware : gestion des versions, configurations nécessaires, paramètres
- les moyens de distribuer la charge et gérer le canary deployment (load-balancer, reverse proxy, dns, …)
- les paramètres des applications permettant de rendre l’installation standard et adaptable dynamiquement à l’environnement, les données, les usages (fichiers de configuration, système clé/valeur, …)
- les codes applicatifs et leur livraison : docker/lxc/vm, packaging
Chaque sujet peut être pris en charge indépendamment des autres et peut-être par une équipe ou une personne différente. Idéalement on montera l’accastillage dans l’ordre proposé ici pour des raisons d’homogénéisation en gardant constamment en tête que tout doit être agnostique de l’environnement (dev, test, homolo, prod), pouvoir être monté et démonté sans laisser de trace et doit être total, on ne fera pas d’ajustement à la main à la cible.
Si besoin il faudra également gérer la partie complexe des chargements des données dans les systèmes de stockage comme les bases de données, les systèmes clé/valeur, les services de fichiers (NAS, S3 ou volume disque). On pourra s’appuyer sur les outils de manipulation des schémas, de création de volumes, de virtualisation des stockages pour gagner du temps, de la place et sécuriser également les manipulations.
Beaucoup de travail en perspective si vous n’avez commencé aucun travaux sur l’automatisation, l’infrastructure cloud, l’automatisation ou l’orchestration, mais ça vaut vraiment le coup et on peut y aller de façon très progressive. Le simple fait de monter des composants de façon automatique est déjà une grande victoire et permet de libérer du temps et de l’énergie au sein des équipes pour faire avancer les autres travaux.
Bilbio
- O’Reilly - An introduction to immutable infrastructure 2015
- Highops - Immutable infrastrucrue: 6 questions to 6 experts 2014
- Codeship - Why You Should Build an Immutable Infrastructure 2017
- Dell EMC Immutable Infrastructure Myth or Must? 2016
- sumo logic - Understanding Mutable and Immutable Infrastructure
- Martin Fowler - Canary Release 2014
- RBAC (Wikipedia)
Photo from Mike Wilson