Les 5 outils piliers de notre orchestration cloud

William Brundu, Codéin
William Brundu

Une orchestration complète des infrastructures client nécessite la mise en œuvre d'un certain nombre d'outils remplissant chacun un rôle particulier dans la chaîne d’automatisation.

Notre vision d’une infogérance moderne implique l’automatisation de la gestion des infrastructures. Cela nous permet de les mettre à disposition plus rapidement tout en minimisant le risque d’erreur et facilite l’autonomie des parties prenantes des projets.

En tant qu’infogéreur, il est indispensable de standardiser au maximum tout en permettant une grande flexibilité.

Nous avons donc opté pour des outils libres : le libre est dans l’ADN de Codéin et nous offre la possibilité de travailler avec les développeurs ou remonter les bugs et modifier les solutions choisies. Nous avons par exemple été amenés à le faire avec les plugins Ansible-Netbox et Terraform-Outscale.

Nous nous sommes outillés en ce sens tout en prenant soin de garder une complexité modérée et une bonne maintenabilité.
Par le biais de cet article, nous allons vous présenter les principaux outils qui composent notre orchestration, ainsi qu’un aperçu de leurs interactions.

  1. Ansible
  2. Netbox
  3. Terraform
  4. Packer
  5. Rundeck

 

Ansible 

 

Ansible

 

Ansible est un outil libre écrit en python et développé par Red-Hat. Il sert à automatiser la configuration système de façon déclarative en YAML.

Il a été choisi parce que nous avions déjà une très bonne expérience avec, qu'il est très facile à prendre en main et à utiliser, et a une grosse communauté : cela nous garantit une interopérabilité plus rapide à mettre en œuvre lorsqu'il s'agit de le combiner avec d'autres outils. 

La réutilisabilité du travail avec Ansible se présente sous la forme de rôles. On écrit de la configuration Ansible de façon générique et réutilisable, au moyen de variables et quelques algorithmes simples, pour remplir une fonction bien précise comme la configuration de services comme Apache, PHP, un cluster Galera...

Les rôles doivent-être idempotents : des lancements subséquents ne doivent pas provoquer de changements s'il n'y a eu aucune intervention sur le système.

L'objectif de ces rôles est de pouvoir déployer les services courants que nous utilisons de manière automatique.

Avec le temps, nous avons écrit de nombreux rôles et utilisé certains écrits par la communauté lorsqu'ils étaient satisfaisants pour notre usage. La totalité des services que nous déployons sont installés et configurés par Ansible.

La difficulté lors de l'écriture d'un rôle est de savoir où positionner le curseur entre la customisation et la simplicité d'usage et de maintenance : Un rôle très customisable est souvent complexe et/ou pénible à maintenir au fil des versions (du composant en lui-même ou d'Ansible). A contrario, un rôle trop simpliste nécessite de configurer un certain nombre de choses.

Afin de réduire la pénibilité des tests vu le nombre grandissant de rôles que nous commencions à avoir, nous avons aussi fait le choix d'automatiser leurs tests avec un outil nommé Molecule. Nous l'utilisons de manière relativement simple : lorsqu'un commit est poussé sur le projet git du rôle, GitLab-ci déclenche une tâche molecule qui s'occupe de le tester pour chaque version de distribution Linux que nous supportons.

 

Nous avons principalement 4 usages d'Ansible chez Codéin:

  • la configuration des systèmes lors de l'initialisation d'une infrastructure
  • les éventuelles modifications des systèmes sur toute la phase de maintien en conditions opérationnelles des infrastructures pour garantir la traçabilité des changements (git) et leur reproductibilité
  • l'installation et la livraison des nouvelles versions des applications
  • le maintien de configuration sur tout notre parc

Pour ce dernier point, nous avons des playbooks dédiés qui sont exécutés à intervalles réguliers sur l'entièreté de notre parc de machines pour centraliser certaines configurations et maintenir une cohérence au niveau :

  • des accès (filtrage IP et clés SSH)
  • du monitoring et de la métrologie
  • de certaines règles de sécurité génériques
  • des sauvegardes
  • référencement de certaines informations système dans notre outil de gestion de parc 

Ansible étant relativement lent, il faut veiller à ce que ce maintien de configuration reste le plus léger possible pour qu'il continue de s'exécuter dans des délais acceptables sur un très grand nombre de machines.

De plus, pour ne pas avoir à maintenir un inventaire Ansible statique pour chacune des machines de chaque projet, nous utilisons notre outil de gestion de parc Netbox comme inventaire dynamique : ansible requête l'API de netbox à chaque lancement pour savoir quelles sont les machines à cibler et les groupes dont elles font partie.

 

Netbox

 

Netbox

 

Netbox est un outil libre écrit en python initialement développé par Digital Ocean pour leurs besoins. 
Ses rôles sont généralement décrits par plusieurs noms : CMDB (Configuration Management DataBase), DCIM (Data Center Infrastructure Management) et IPAM (IP Address Management).

Nous avons sélectionné Netbox pour deux raisons :

  • avoir une vue d'ensemble de notre parc de machines (physiques et virtuelles) et IP pour des besoins de reporting et de référencement
  • avoir un inventaire dynamique pour Ansible

Le premier point concerne l'objectif principal de Netbox : classifier les objets d'infrastructures informatiques avec des attributs spécifiques. A première vue, il semble plutôt fait pour gérer des datacenters mais son modèle s'adapte très bien même lorsqu'on ne possède pas directement le matériel : location de serveurs chez OVH, machines virtuelles dans le cloud...

Le second point était un prérequis que nous avions : l'outil devait disposer d'une API afin de pouvoir développer un plugin d'inventaire Ansible. Dans le cas de Netbox, le plugin était déjà existant.

Netbox nous sert donc de référence pour le référencement de nos machines, des adresses IP et réseaux utilisés, mais aussi pour la spécification de certaines valeurs permettant de configurer notre parc.

Il est possible d'attribuer à la plupart des objets dans netbox des ensembles de clés/valeurs pouvant fonctionner avec un mécanisme d'héritage : les "config contexts". Un objet enfant hérite des clés/valeurs d'un objet parent, tout en ayant la possibilité de les surcharger sur l'objet enfant. 

Cela nous permet de centraliser et hiérarchiser certaines configurations, tout en permettant à Ansible d'utiliser ces valeurs via l'inventaire dynamique.

Nous alimentons Netbox avec Ansible, pour lequel il existe un module dédié. Cela nous permet de conserver les données dans git pour historiser et avoir la possibilité de le renseigner à nouveau si besoin. 

Nous avons cependant deux méthodes pour le renseigner :

  • La première est manuelle : nous écrivons un fichier YAML décrivant les objets que nous voulons ajouter ou modifier. Ansible gère ensuite la communication avec l'API netbox. Cette méthode manuelle est utilisée pour les infrastructures statiques, comme la gestion des hosts physiques de notre cloud privé.
  • La seconde est automatique : dans le cadre des infrastructures gérées avec Terraform, c'est Terraform lui-même qui a déjà connaissance des informations nécessaires au référencement dans Netbox. Lorsqu'une machine est créée, elle est automatiquement ajoutée à Netbox avec les bonnes valeurs. De la même façon, elle est retirée lorsqu'elle est détruite. Cela nous permet d'avoir une source unique de vérité à jour, et nous baser dessus pour les diverses opérations du quotidien.

S'agissant d'une brique centrale à notre fonctionnement, l'authentification à Netbox se fait au travers de notre SSO et il rentre dans le cadre d'un plan de reprise d'activité en cas d'incident majeur.

 

Terraform

 

Terraform

 

Terraform est un outil d'Infrastructure as Code libre écrit en Go servant à créer, modifier et détruire des composants d'infrastructure de façon déclarative en HCL, un langage de configuration de la société Hashicorp éditrice de Terraform.

Nous avons choisi cet outil libre pour les mêmes raisons qu'Ansible : facile à prendre en main et à utiliser, avec une grosse communauté. Il s'agit de la référence dans les outils d'IaC et nous possédions déjà une grande expérience avec cet outil.

Son support multi-cloud et le grand nombre de plugins existants en ont fait la solution à privilégier pour codifier de l'infrastructure, que ce soit sur du cloud public ou privé.

Depuis quelques années, l'outil est devenu mature et stable : la maintenance du code est beaucoup moins laborieuse que par le passé.

La réutilisabilité du travail avec Terraform se présente sous la forme de modules. De la même façon qu'Ansible, la configuration peut être déclarée de façon générique et réutilisable en utilisant des variables et quelques algorithmes simples.

Un module peut combiner la création d'infrastructures sur plusieurs "providers" (fournisseurs de cloud, SaaS...) et permettre de déployer plusieurs centaines d'éléments à la fois (réseau, sécurité, système, services...).

Il nous permet chez Codéin de :

  • pouvoir bénéficier d'un langage unique pour créer de l'infrastructure sur de multiples providers
  • standardiser, réutiliser et intégrer l'infrastructure dans des workflows d'automatisation
  • collaborer efficacement par le biais d'outils comme Git

Pour ceux qui ont déjà expérimenté les interfaces des services de IaaS, PaaS, SaaS, il peut être pénible de configurer de nombreux éléments à la suite dans ces interfaces : les lenteurs, les erreurs éventuelles commises, le souci de garder une cohérence dans la façon de faire les architectures… nous font rapidement comprendre les bénéfices d'un outil comme Terraform au quotidien.

Rentrer dans les détails dépasserait largement le cadre de cet article, mais chez Codéin nous utilisons Terraform pour gérer tout ce qui est créé sur les cloud providers que nous utilisons (Outscale, OVH Cloud, Azure…), de l'initialisation aux modifications tout au long du cycle de vie du projet. 

Outre le fait que cela nous permet de garantir la traçabilité des changements (git) et leur reproductibilité, il nous est indispensable de pouvoir créer, détruire, modifier et dupliquer des infrastructures à souhait.
Avec un code Terraform bien pensé pour cela, il est possible d'arriver à cet objectif
.

Pour avoir une automatisation complète, terraform doit passer de l'information à Ansible. Ne serait-ce que pour qu'Ansible sache sur quelle machine se connecter et comment, afin de configurer le système.

Il y a de nombreux moyens de faire cela. Nous utilisons plusieurs méthodes:

  • utilisation des fonctionnalités de tag des machines sur les cloud providers, tags que nous récupérons avec ansible en guise de facts
  • Terraform qui créé des fichiers YAML ou JSON utilisés par ansible en guise de facts
  • automatisation du renseignement de notre outil de gestion de parc (Netbox) par terraform: à l'exécution, terraform exécute un job qui se charge de renseigner et mettre à jour les informations de base (nom des machines, IP, réseaux…) afin qu'ansible puisse à son tour utiliser netbox comme inventaire et configurer les machines.

Nous utilisons aussi Terraform pour générer des variables nécessaires à notre utilisation de Packer, outil servant à créer des images disque pré-configurées.

 

Packer

 

Packer

 

Packer est un outil libre écrit en Go et édité par la société Hashicorp permettant de créer des images disques pour de multiples cloud providers par le biais d'un fichier de configuration écrit en JSON ou HCL (Hashicorp Configuration Language). 

Son fonctionnement est relativement simple : une machine va être démarrée sur un cloud provider choisi et des "provisioners" (shell, ansible...) vont être exécutés sur cette machine. Une fois exécutés, la machine va être éteinte, une image disque sera créée puis la machine sera détruite.

Packer est un allié de choix dans l'orchestration d'infrastructures dynamiques, en nous permettant de fiabiliser les déploiements et de pouvoir rollback simplement à une version donnée de l'application.

Nous l'utilisons chez Codéin principalement, car il nous permet d'adapter l'infrastructure efficacement sur des projets avec des contraintes de charge variables et de gagner du temps sur les créations d'environnements.

Dans le chapitre précédent, nous évoquions la génération de variables Packer par Terraform. Cela est dû au fait que certaines applications doivent pouvoir se connecter à la base de données ou un autre service de l'environnement pour être construites.

Dans ces conditions, il devient quasi indispensable que la machine démarrée par Packer pour créer l'image soit présente dans l'environnement cible, pour que l'application puisse accéder à certaines données. C'est précisément pour cette raison que nous utilisons Terraform pour générer des variables qui seront utilisées par packer pour démarrer la machine : le VPC, le subnet, les security groups... et toutes les choses qui permettront à cette machine temporaire de communiquer avec les services.

En effet, dans un modèle où les environnements sont créés et supprimés à la demande, la source de ces informations reste Terraform.

Terraform nous permet de créer l'infrastructure et Ansible permet de configurer les systèmes et déployer les applications. Pourquoi avons-nous besoin d'un outil pour générer des images ?

Admettons que nous voulions pouvoir faire varier le nombre de serveurs web pour répondre à une fluctuation du trafic : il suffirait a priori d'indiquer à terraform de créer des machines supplémentaires et à ansible de les configurer.

Cependant, le temps entre lequel la décision de scaling est prise et l'entrée en fonctionnement des nouveaux serveurs web doit-être le plus faible possible, et l’opération doit-être fiable.

Si nous laissons à Ansible le soin de configurer entièrement les serveurs à chaque opération de scaling, il peut se passer plusieurs minutes avant que les nouveaux serveurs soient opérationnels, même dans le cas où tout se passe correctement.

Nous sommes soumis à tous les aléas imaginables : un dépôt de paquet qui ne répond pas ou a changé depuis la dernière utilisation, ou n'importe quel autre service nécessaire à la configuration de la machine ou au build de l'application qui serait indisponible au moment de la création du serveur.

Pour pallier ces problèmes, nous préparons à l'aide de Packer des images disques avec le maximum déjà installé, configuré, le build de l'application déjà réalisé. Nous obtenons ce qui est communément appelé une "golden image".

Pour les serveurs web, une nouvelle image est créée à chaque nouvelle version de l'application à déployer. Elle contient absolument tout ce qui est nécessaire pour que le service soit rendu lorsqu'un serveur est démarré à partir de cette image. Aucune modification n'est réalisée par la suite. 

Cela permet de s'assurer que toutes les machines démarrées à partir de cette image fonctionnent de la même façon que les précédentes, et soient opérationnelles dans un délai minimal : le temps de boot.

Dans une moindre mesure, nous préparons quand c'est possible une image disque pour chaque type de serveur (proxy, databases...) avec le maximum de services installés et pré-configurés afin de gagner du temps lors de la création d'un environnement. Nous utilisons la fonctionnalité de tags dans nos rôles ansible ce qui nous permet de limiter leur application : une certaine partie des tâches portera le tag "install" et une autre partie "config".

Lors de la création d'une image disque template, nous appliquons les rôles Ansible en limitant avec le tag "install", pour éviter de configurer des choses qui devront de toute façon être adaptées en fonction de l'environnement. 

Lorsque nous utilisons ces images pour créer des environnements, nous appliquons cette fois-ci les rôles Ansible en limitant avec le tag "config" ce qui permet de se limiter aux tâches de configuration des services en fonction de l'environnement. 

Cela nous permet de gagner un temps précieux à la création, les tâches coûteuses en temps comme le téléchargement et l'installation de paquets ayant déjà été réalisées.

Packer est très pratique, mais il est tout de même nécessaire de l'outiller avec quelques scripts parce qu'il ne permet pas, par exemple, de gérer la rétention des images.

Globalement, lorsqu'on souhaite une orchestration complète nécessitant d’enchaîner et combiner plusieurs outils, il devient nécessaire de se tourner vers un orchestrateur. Chez Codéin, nous avons choisi Rundeck, un outil à découvrir dans le chapitre suivant.

 

Rundeck

 

Rundeck

 

Rundeck est un outil libre écrit en java et développé par PagerDuty. 

Il permet d'orchestrer l'exécution de scripts et d'outils existants, expose une interface web ainsi qu'une API et intègre une gestion des utilisateurs et des droits. 

Outre l'orchestration, il permet de donner le droit à certains utilisateurs d'exécuter une tâche, sans pour autant donner accès à des identifiants sensibles.

Cela évite de maintenir de nombreuses procédures utilisateurs plus ou moins complexes et pouvant-être source d'erreurs: si une tâche récurrente doit-être régulièrement réalisée par un administrateur système qui n'a aucune valeur ajoutée excepté bénéficier des droits suffisants, il vaut alors mieux l’automatiser et permettre à l'utilisateur de la réaliser seul par le biais de rundeck.

Nous avions initialement commencé par utiliser gitlab-ci pour automatiser un certain nombre de choses. Cependant, lorsqu'il s'agit de donner des droits à des utilisateurs pour réaliser telle ou telle action, gitlab-ci montre vite ses limites: il n'est pas fait pour cela.

Rundeck nous a principalement servi pour orchestrer toutes les briques et les différents outils/scripts mis en place afin de gérer les plateformes web de nos clients. Il nous permet d'enchaîner des actions pour créer des workflows, de prévoir quoi faire en cas d'erreur, avertir en cas de succès ou d'échec et communiquer avec d'autres outils via des webhooks.

Nous l'utilisons pour des besoins internes, par exemple pour planifier des tâches récurrentes comme le maintien de configuration, mais aussi comme plateforme de self-service pour les utilisateurs.

Actuellement, nous donnons aux utilisateurs au travers de rundeck la possibilité de réaliser toutes sortes d'actions sur leur infrastructure cloud dans le cadre de notre offre Codéops.

Par exemple :

  • créer une nouvelle release (image disque)
  • déployer une nouvelle release ou rollback vers une ancienne (déploiements blue-green)
  • créer un nouvel environnement à partir des données d'un environnement existant
  • détruire un environnement
  • augmenter ou réduire le nombre de serveurs web (scaling)
  • mettre en maintenance
  • et bien plus encore, en fonction des besoins...

La mise à disposition de ces fonctionnalités permet de casser les silos entre les administrateurs systèmes et les développeurs en rendant ces derniers aussi autonomes que possible. Les bénéfices majeurs sont une réactivité accrue et une fiabilisation des actions récurrentes grâce à leur automatisation.

 

Conclusion

Tous les outils que nous venons de présenter, une fois assemblés et orchestrés, forment la base de notre offre Codéops : notre offre d’infogérance vous permettant de piloter votre infrastructure et votre budget cloud au travers d’une application web développée par nos soins.

Solution de gestion clé en main de votre applicatif sur cloud public Découvrir Codéops
Solution de gestion clé en main de votre applicatif sur cloud public Découvrir Codéops

A lire aussi

Et vous, devez-vous migrer votre site web vers le cloud ?
Au cœur du service hosting de Codéin
Voir tous les articles