IaC : De l'infrastructure manuelle à l'Infrastructure as Code
« En traitant l’infrastructure comme du code, vous créez un moyen reproductible et fiable de gérer et d’approvisionner votre environnement ». La vision de Patrick Debois nous montre la puissance du concept d’Infrastructure as Code aussi appelé IaC. Comme il le décrit brièvement, l’IaC est une manière de penser un système d’infrastructure sous forme de code afin de le rendre plus lisible, efficace et maintenable. C’est avec cette vision que j’ai été amené à utiliser le concept d’Infrastructure as Code au sein de l’infrastructure du Ministère des Armées. Étant donné que la réalisation s’est déroulée au sein du Ministère des Armées dans un contexte sensible, certaines informations ont été volontairement omises.
Comment le concept d’Infrastructure as Code s’est-il imposé dans le projet ?
Lors de mon stage au Ministère des Armées, j’ai eu pour mission de mettre en place un système permettant de déployer un cluster Kubernetes et de le répliquer sans restriction. Un cluster en informatique est un ensemble de plusieurs machines interconnectées (généralement des machines virtuelles). Elles travaillent ensemble pour optimiser la performance, la haute disponibilité et la redondance des applications qu’elles font fonctionner. Kubernetes est une des technologies permettant de faire des clusters hautement disponibles. Pour y parvenir, j’ai défini les différentes contraintes. Pour commencer, l’infrastructure devait fonctionner sous le système d’exploitation Debian 12. Elle devait être réplicable rapidement, tout en étant hautement disponible. Elle devait aussi fonctionner hors-ligne. Pour y parvenir, j’ai utilisé le concept d’Infrastructure as Code qui répond à toutes ces contraintes. Dans un premier temps, l’IaC m’a permis de définir et de créer des machines virtuelles en utilisant l’hyperviseur KVM. Une machine virtuelle en informatique est un logiciel qui permet de créer un ordinateur à l’intérieur d’un vrai ordinateur. Grâce à cette notion, il est possible de diviser un ordinateur physique en plusieurs machines virtuelles pour améliorer la répartition de l’utilisation des ressources ainsi que la sécurité. KVM est un hyperviseur, c’est-à-dire qu’il s’agit du logiciel qui pourra créer et gérer les machines virtuelles. Dans un second temps, l’IaC m’a permis de configurer les machines virtuelles, puis d’y installer toutes les dépendances nécessaires pour mettre en place un cluster Kubernetes. Pour parvenir à ce résultat, j’ai dû faire énormément d’essais, notamment dû à l’environnement hors-ligne qui causait beaucoup d’erreurs à cause des dépendances qui étaient inaccessibles. J’ai donc très souvent supprimé, puis remis en place l’infrastructure à l’aide des configurations qui la définissaient sous forme de code. Ce concept d’IaC m’a permis de gagner énormément de temps et m’a permis de finaliser le projet. Sans lui, je n’aurais pas pu corriger aussi rapidement toutes les erreurs que j’ai rencontrées lors de la mise en place du cluster. C’est pour toutes ces raisons que la réalisation d’une Infrastructure as Code était nécessaire au sein de ce projet de création de cluster Kubernetes.
Quel était le contexte initial du projet ?
Dans le cadre de mon Master Expert des Systèmes d’Information à l’ESIEA, j’ai été amené à réaliser un stage de six mois et une alternance de deux ans au sein du Ministère des Armées à Paris. Il s’agit d’un organisme qui dispose de nombreux points d’accroches dans toute la France et qui regroupe tous les corps de métier. Dans cet organisme, j’évoluais dans un environnement avec de fortes contraintes de sécurité. Par exemple, je n’avais pas accès aux dépendances sur le réseau Internet. Durant le stage, j’ai été amené à travailler en tant qu’administrateur SRE sur une solution d’Infrastructure as Code (IaC). Le rôle d’un administrateur SRE est d’assurer la fiabilité, la performance et la disponibilité des systèmes d’informations d’une entreprise. Pour cela, l’administrateur SRE travaille sur l’automatisation et l’optimisation des processus de développement, de déploiement et de livraison. C’est dans ce cadre que j’ai été amené à travailler sur ce projet.
Lors du projet, j’ai dû réaliser une solution pouvant créer une infrastructure Kubernetes hors-ligne. L’intérêt de cette solution d’infrastructure est de simplifier la publication des applications développées au Ministère des Armées, tout en garantissant une gestion efficace des problèmes éventuels. L’enjeu est d’introduire une première approche de la méthodologie DevOps au sein d’une équipe de développeurs web. Le DevOps est une culture qui vise à automatiser, superviser et optimiser les processus de développement au sein des équipes de développeurs pour améliorer la qualité et l’efficacité des livraisons.
Dorénavant, les équipes de développeurs et les équipes opérationnelles doivent collaborer plus activement. Pour y parvenir, la culture DevOps est applicable. Si on applique ces principes au sein des équipes, le DevOps va permettre d’automatiser les processus de déploiement, de tests, de livraison et de surveillance. Par conséquent, il y aura moins d’erreurs humaines et les équipes pourront se concentrer sur des tâches ayant une valeur ajoutée plus élevée dans les projets.
Dans un premier temps, j’ai eu pour objectif de réaliser une veille technologique pour sélectionner les outils et les technologies à utiliser. J’ai commencé par définir les différents besoins. Pour commencer, l’infrastructure doit être résiliente afin de permettre à l’administrateur SRE de restaurer l’application à un état fonctionnel précédent en cas de défaillance. La solution doit fonctionner sous Debian et être opérationnelle sans accès à Internet. La solution d’infrastructure doit être hautement disponible, ce qui signifie qu’il doit y avoir un minimum d’interruptions de service pour les utilisateurs. En cas d’erreur sur un service, une copie de celui-ci prendra automatiquement le relais. C’est ce que l’on appelle la redondance. Elle devra aussi être complètement portable sur d’autres machines utilisant Debian. Les équipes chargées de l’administration de la solution devront pouvoir détecter les erreurs ainsi que leur provenance. Dans ce cadre, un système de supervision devra être mis en place. Enfin, un système de répartition de charge doit également être mis en place pour optimiser la distribution de la charge sur l’infrastructure. En regroupant ces différents besoins, deux technologies en sont ressorties pour créer l’Infrastructure as Code. Il s’agit d’Ansible ainsi que de Puppet. Mon choix s’est tourné vers Ansible, car contrairement à Puppet il n’avait pas besoin d’installer un agent sur chaque machine à gérer. Ansible avait l’avantage de n’avoir aucune configuration supplémentaire à effectuer sur les machines composant l’infrastructure. Pour ce qui est de la technologie pour rendre les services hautement disponibles, une seule correspondait à tous ces critères. Il s’agissait de Kubernetes. Finalement, j’ai dû m’autoformer sur ces dernières durant une période de deux semaines.
Dans un second temps, j’ai dû mettre en place la solution d’infrastructure en suivant la méthodologie Agile. Cette approche améliore la disponibilité des outils ainsi créés. Plusieurs besoins en sont ressortis. Je devais pouvoir créer, configurer et supprimer des machines virtuelles à la demande en utilisant uniquement le projet. Il fallait aussi y installer des logiciels particuliers si nécessaire. Enfin, le projet devait être capable de fonctionner dans un environnement déconnecté d’Internet. Une fois la solution créée, j’ai dû déployer une ou plusieurs applications pour en valider le bon fonctionnement. Une application se compose d’un ou plusieurs services qui communiquent entre eux, constituant ainsi le test le plus approprié pour cette solution d’infrastructure. Dans ce cadre, j’ai dû faire attention à répondre à toutes ces contraintes.
Malgré tous les avantages des solutions et des technologies choisies, un gros risque en ressort. Si je ne maîtrise pas suffisamment les technologies que je vais utiliser, un risque de complexification du code et de l’infrastructure risquerait de survenir. Par exemple, un des principaux intérêts d’Ansible est d’être accessible techniquement en étant lisible. Nous ne souhaitons surtout pas ça. Le projet deviendra moins maintenable et les équipes qui reprendront le projet perdront sûrement beaucoup de temps pour le comprendre. Dans ce cadre, il est très important de faire attention à la complexité du code et de l’infrastructure. Je devrais passer par une phase de formation concrète avant de me lancer dans le projet.
Quelles ont été les étapes principales du déroulement de ce projet ?
1. Préparation du projet.
Dans cette première phase du projet, j’ai dû définir les technologies et les outils à utiliser. Il s’agit de la phase la plus importante du projet. Dans le cas où j’amène le projet dans une mauvaise direction, cela pourrait condamner la réussite du projet. Les outils choisis doivent répondre aux besoins et être le plus simple possible d’apprentissage pour les employés. Le projet a un intérêt sur du long terme. Si les technologies et les outils choisis ne sont pas en adéquation avec le projet. Il risque de ne pas être maintenu sur du long terme. J’ai donc passé deux semaines complètes à me documenter et à réaliser des benchmarks. J’ai dû présenter mon travail à mon tuteur en entreprise afin qu’il oriente et valide mon choix. Puis, j’ai passé deux semaines supplémentaires à me former sur les outils sélectionnés. Les deux principaux outils qui ont été sélectionnés pour ce projet sont Ansible et Kubernetes.
Tout au long du projet, j’ai utilisé la méthode SCRUM de la méthodologie Agile. Cette méthode permet de changer rapidement la direction d’un projet si nécessaire. Elle permet d’améliorer la productivité des équipes et d’optimiser les livraisons de fonctionnalités grâce à un fonctionnement de livraison par période de deux à trois semaines. Avec la méthodologie Agile, les besoins du client sont placés au centre des priorités du projet. Pour que le code du projet soit en adéquation avec la méthodologie Agile, j’ai utilisé l’outil de gestion de projet Git. Cet outil est une pierre angulaire dans tous les projets Agile. Il permet de faciliter le travail en équipe sur un même projet tout en gérant les différentes versions d’un projet. C’est un outil indispensable pour toutes les personnes travaillant dans l’informatique.
Durant le projet, j’ai dû documenter l’intégralité des étapes réalisées. Pour y parvenir, j’ai décidé d’utiliser un langage pour structurer cette dernière. Mon choix s’est tourné vers Markdown. Il s’agit du langage de documentation intégré par défaut dans les projets Git. Il permet de structurer et de styliser des fichiers de documentation facilement et rapidement. De plus, l’intégralité des équipes de développement et opérationnelles le maîtrise. Par conséquent, il s’agissait du candidat idéal pour la documentation du projet. Au niveau de cette étape, j’ai dû particulièrement faire attention à la vulgarisation. L’intérêt était d’en faire une force pour que le projet soit plus facilement adopté par les équipes du Ministère des Armées.
En conclusion, les spécificités, besoins et méthodes utilisés pour le projet sont parfaitement en adéquation avec l’approche DevOps. La veille technologique que j’ai effectuée a été nécessaire pour initier et orienter le projet. Cependant, elle n’a pas suffi à anticiper toutes les dépendances liées à l’environnement hors-ligne. Prévoir ces aspects est complexe, surtout dans un environnement en dehors du réseau Internet où les outils ne sont pas majoritairement censés fonctionner. De plus, je manque d’expérience puisqu’il s’agit de ma première expérience professionnelle. Dans ce contexte, l’environnement hors-ligne m’a exigé de maintenir un rythme d’autoformation soutenu tout au long du proje.
2. Réalisation du projet.
a. Machines virtuelles.
La solution est entièrement basée sur des machines virtuelles. Une machine virtuelle est un système d’exploitation invité qui fonctionne au sein d’un système d’exploitation hôte. En d’autres termes, elle permet d’exécuter un second système d’exploitation, isolé dans une fenêtre, comme une application. Une machine virtuelle présente plusieurs avantages. Elle permet d’optimiser les ressources matérielles en allouant le nécessaire dynamiquement. Une machine hôte, souvent physique, peut héberger plusieurs machines virtuelles. Le nombre de machines virtuelles possibles dépend des ressources matérielles disponibles. Une machine virtuelle est donc un système d’exploitation virtualisé se trouvant à l’intérieur d’un autre système d’exploitation, comme nous pouvons le voir ci-dessous :
Dans un premier temps, j’ai utilisé Qemu pour générer manuellement mes premières machines virtuelles pour me familiariser avec l’outil. Néanmoins, pour créer une solution d’infrastructure flexible et hautement disponible, il est nécessaire que cette infrastructure puisse être créée, configurée et supprimée à volonté. Par conséquent, j’ai automatisé la génération des machines virtuelles avec l’outil d’Infrastructure as Code, Ansible. Cette étape a été relativement rapide, car Qemu peut être utilisé en ligne de commande et dispose d’une documentation exhaustive. Pour utiliser Ansible, il est nécessaire de créer des groupes de tâches ayant le même objectif. Chaque groupe de tâches est défini dans un fichier de configuration Ansible, appelé rôle. Le premier rôle que j’ai créé permet de générer des machines virtuelles à la volonté. Il y a aussi des variables configurables qui permettent de définir les ressources matérielles allouées à chaque machine virtuelle (stockage, mémoire vive, cœurs de processeur, etc.) ainsi que leur identité (nom, description, etc.).
Ensuite, il est essentiel de pouvoir identifier rapidement la fonction des machines virtuelles ainsi que l’environnement dans lequel elle se trouve (développement, qualification, production). Chaque environnement a un niveau de criticité différent. Pour cela, chaque machine virtuelle doit être différenciée à l’aide d’un MOTD personnalisé. Un MOTD (Message of the Day) est un message de bienvenue qui apparaît lors de la connexion à une machine virtuelle et qui indique les informations essentielles de la machine pour la différencier des autres. Le premier rôle de cette étape ajoute un MOTD unique à chaque machine virtuelle. Le deuxième rôle connecte un dépôt externe, permettant de télécharger toutes les dépendances nécessaires aux étapes suivantes sans passer par le réseau Internet. Le troisième rôle connecte un DNS, permettant d’accéder aux machines via son nom et non pas via son adresse IP. Pour finir, un dernier rôle installe l’outil Docker. Il s’agit d’un outil indispensable pour la gestion des futurs services exécutés sur cette infrastructure. La réalisation de tous ces rôles a pris une semaine. Cette étape est importante, car elle constitue la base du projet. Il est donc essentiel qu’elle soit solide, flexible et configurable, selon les besoins. Tel que montré précédemment, tous les rôles sont configurables via un fichier de variables fourni par Ansible au format YAML. Par exemple, si une machine virtuelle a besoin de plus de stockage, cela peut être spécifié facilement dans ces mêmes fichiers de configuration.
b. Dépendances (DNS, Certificate Authority, Artifact Repository)
Pour que le cluster Kubernetes fonctionne. Plusieurs dépendances doivent être mises en place. J’ai commencé par la création d’un DNS que j’ai défini dans le projet Ansible. Un DNS dans une infrastructure présente un grand avantage, il permet de faire correspondre les adresses IP avec des noms de domaine. Les machines virtuelles sont par conséquent plus facilement accessibles et identifiables. Pour cette raison, j’ai intégré un DNS au sein du réseau interne pour simplifier et accélérer la manipulation des machines virtuelles. Le DNS est critique au sein de l’infrastructure. En cas de panne, l’ensemble de l’infrastructure pourrait être affecté. Pour éviter ce cas, j’ai mis en place deux DNS : un maître et un esclave. C’est essentiel, car si le DNS maître tombe en panne. Le DNS esclave reprendra la charge. De plus, le DNS esclave se met à jour automatiquement lorsque des modifications ont lieu sur le DNS maître. Il est donc autonome. Il s’agit par conséquent d’un système optimal pour assurer la fiabilité et la disponibilité du DNS au sein de l’infrastructure. Lors de l’initialisation d’une machine virtuelle au sein du cluster, un nom de domaine lui est automatiquement attribué en fonction de la configuration du projet Ansible. La création et la gestion du DNS sont réalisées intégralement via un rôle Ansible. Ce rôle s’appuie sur le service bind9 pour la création des DNS.
Par la suite, j’ai dû mettre en place un Certificate Authority. Il s’agit d’une dépendance obligatoire qui va permettre de créer et de gérer des clés de sécurité pour toute l’infrastructure. Il va jouer un rôle crucial au sein de l’infrastructure, car il va assurer la sécurité des connexions entre les machines virtuelles et les applications. J’ai créé un rôle Ansible pour mettre en place l’outil openssl. Il s’agit de l’outil qui va me permettre de créer le Certificate Authority et les clés de sécurité requises. Finalement, le projet Ansible s’occupe aussi de créer et de distribuer les clés de sécurité là où c’est nécessaire. J’ai rencontré des difficultés lors de la configuration des certificats. Cependant, j’ai résolu le problème de configuration avec l’aide d’un intervenant d’une autre équipe. J’avais omis de spécifier les IP et les noms de domaine qui devaient être valides au niveau des clés de sécurité avant de les créer.
Pour finir, j’ai mis en place un Artifact Repository avec l’outil Nexus 3. Cet outil permet de centraliser les différents dépôts qui stockent les dépendances de l’infrastructure. Initialement, je créais des dépôts individuels, mais j’ai migré vers Nexus 3 pour sa flexibilité et sa gestion avancée des dépendances et des versions. Nexus 3 m’a permis de gérer plusieurs types et versions de dépendances de manière centralisée, augmentant ainsi la flexibilité de l’infrastructure. J’ai créé un rôle pour le créer et le gérer.
En conclusion, l’intégration d’un DNS, d’un Certificate Authority et d’un Artifact Repository a pris plusieurs semaines, mais ces éléments sont essentiels pour la sécurité et la flexibilité de l’infrastructure DevOps. Ces outils permettent de gérer efficacement les dépendances et d’assurer des connexions sécurisées. Ils facilitent ainsi le déploiement et la gestion des services au sein de l’infrastructure.
c. Kubernetes.
Maintenant que nous avons toutes les dépendances installées, configurées et que nous pouvons créer des machines virtuelles à volonté. Il ne me reste plus qu’à installer Kubernetes sur toutes les machines virtuelles pour rendre le projet fonctionnel. Dans cette dernière étape, je vais utiliser l’outil K3s qui permet de créer un cluster Kubernetes plus rapidement. Cet outil est un point clé du projet, car il va permettre de me faire gagner énormément de temps et de rendre ce projet réalisable dans le temps imparti.
Kubernetes est un outil basé sur Docker. Docker est une technologie qui permet d’enfermer des applications avec toutes leurs dépendances dans des environnements isolés qui sont appelés conteneurs. Kubernetes quant à lui permet de créer un cluster pouvant accueillir des applications sous forme de conteneur Docker. Sa technologie de clustering permet de maintenir ces applications hautement disponibles. C’est-à-dire qu’elles doivent pouvoir être disponibles 99% du temps sur une année. Il s’assure que toutes les applications fonctionnent correctement, qu’elles peuvent être mises à jour facilement et qu’elles peuvent redémarrer automatiquement en cas de problème. Par conséquent, il s’occupe de rendre les applications hautement disponibles. À la place de Kubernetes je vais utiliser K3s qui est une version modifiée et plus légère de Kubernetes. Cet outil embarque toutes les configurations nécessaires pour mettre en place un cluster. K3s prend les parties essentielles de Kubernetes et simplifie son installation et son utilisation. C’est un outil fiable et léger qui permettra de me faire gagner du temps sur la configuration du cluster Kubernetes.
J’ai commencé par créer un rôle Ansible pour installer K3s. Pour y parvenir, j’avais préalablement déposé les dépendances nécessaires à son fonctionnement dans l’Artifact Repository et créé les certificats de sécurité à l’aide du Certificate Authority. Une fois K3s déployé, j’ai dû opter pour une architecture hautement disponible. Elles sont classées par niveau de disponibilité. J’ai sélectionné l’architecture la plus disponible étant donné que les applications qui fonctionneront dessus seront critiques :
Cette architecture présente l’avantage d’être fortement disponible. Par exemple, si un nœud maître, qui gère l’infrastructure, tombe en panne, l’infrastructure ne sera pas affectée, car d’autres nœuds continueront à fonctionner. Un nœud est une machine virtuelle qui est intégré au cluster Kubernetes. En cas de panne de tous les nœuds maîtres, l’intégralité de l’état de l’architecture est sauvegardée en temps réel dans une base de données externe qui est elle-même répliquée. Les risques de défaillance sont donc considérablement réduits.
Pour conclure, malgré les dépendances supplémentaires liées au fonctionnement en dehors du réseau Internet, K3s est un outil qui simplifie, allège et sécurise Kubernetes. Comparé à ses concurrents, il est le plus riche en fonctionnalités tout en étant le plus léger en termes de consommation de ressources. Ses nombreuses possibilités d’architectures le rendent flexible et capable de répondre à divers besoins. Bien que trois semaines aient été nécessaires pour développer le rôle Ansible permettant d’utiliser K3s, l’utilisation de cet outil est une nécessité et un atout pour le projet. Grâce à cet outil, j’ai pû me former sur de nombreuses notions, comme les Certificate Authority ou encore les Artifact Authority. Ce fut une des phases les plus instructives où j’ai pu mettre en corrélation les compétences apprises au sein de ma formation à l’ESIEA ainsi qu’au sein du Ministère des Armées.
d. Solution finale
Finalement, dans cette première version, nous retrouvons les principes fondamentaux du DevOps. En plus de la solution d’infrastructure que j’ai réalisée en Ansible, j’ai développé un script en Bash qui permet de lancer ou d’arrêter chaque phase de la solution. De cette manière, la solution est encore plus accessible pour les équipes techniques. Le script comprend un système de journalisation. En cas de mauvaises configurations d’un fichier, l’erreur sera enregistrée dans un journal condensé au format texte ainsi que dans un second journal non condensé qui est disponible à la racine de la solution. Le script intègre également l’outil Ansible Lint pour vérifier la qualité du projet s’il est voué à être modifié. Cela permet d’assurer la qualité du code après chaque modification et ainsi sa maintenabilité sur du long terme. Cette fonctionnalité peut être désactivée si nécessaire en modifiant la ligne « DEBUG=true » en « DEBUG=false ». Cette solution est entièrement configurable via des fichiers de configuration au format YAML. Il s’agit donc d’une solution facile à utiliser, que j’ai documentée et qui est flexible.
Lors de la première étape, toutes les dépendances ainsi que les outils nécessaires pour lancer les futurs services sont mis en place. Par exemple, c’est à ce moment que le DNS, le Certificate Authority et l’Artifact Repository sont mis en place. La solution d’infrastructure crée et configure le nombre de machines virtuelles défini dans les fichiers de configuration. Une fois ces machines créées, chaque outil est déployé dans un environnement isolé Docker sur la machine virtuelle qui lui est attribuée. Ces outils sont essentiels pour gérer le déploiement des futurs services.
Lors de la seconde étape, les machines virtuelles dédiées aux applications sont créées puis configurées en fonction des fichiers de configuration du projet. Cette phase peut être supprimée et relancée indépendamment de la première étape, ce qui augmente considérablement la flexibilité et les possibilités de gestion et d’évolution du cluster Kubernetes. Suite à cette phase, les applications peuvent être exécutées sur l’infrastructure.
Finalement, nous pouvons constater que l’objectif est atteint et que nous pouvons exécuter des applications hautement disponibles en dehors du réseau Internet sur notre projet. Nous pouvons créer, modifier, supprimer et dupliquer à volonté l’infrastructure grâce aux propriétés d’Ansible. Par conséquent, nous avons pu prouver que la réalisation d’un projet aussi complexe dans un environnement critique est faisable. Dorénavant, il faudra se concentrer sur la partie supervision que je n’ai pas eu le temps de finaliser, avant de l’utiliser dans un environnement de production. Cette partie est essentielle pour garantir la maintenance des clusters créés avec cette solution. Il est important que les équipes opérationnelles soient prévenues lors des pannes et qu’il soient orientées sur l’origine de la panne. Par conséquent, il s’agit d’une fonctionnalité essentielle sur laquelle il faut encore travailler.