Ansible Inventory Plugins

le 03/05/2019 par Marc Cyprien
Tags: Software Engineering

Les Inventory Plugins sont une nouvelle façon de décrire les inventaires pour Ansible à partir des informations d’un cloud provider. Ces plugins sont disponibles depuis la  version 2.4 d’Ansible et sont une alternative aux inventaires dynamiques. Au travers de cet article, nous allons voir ce que sont ces plugins et comment les utiliser.

Si vous n’êtes pas familier des inventaires dans Ansible, vous pouvez lire l’article qui les présente sur ce blog.

Inventory Plugins Kesako ?

Si vous utilisez Ansible, vous avez sûrement déjà entendu des inventaires dynamiques, qui permettent de récupérer un ensemble d’hôtes Ansible à partir d’un provider externe : cloud provider par exemple, mais aussi DNS, outils d’auto discovery, etc. Ces inventaires dynamiques sont des scripts Python qui sont exécutés par Ansible au lancement de la commande. Ces scripts sont donc à incorporer dans votre code et peuvent être téléchargés depuis le dépôt officiel Ansible vers votre dépôt de code. Vous pouvez aussi développer vos propres inventaires dynamiques en écrivant vous-même le code qui ira interroger votre provider, une CMDB par exemple. Les inventaires proposés par Ansible sont écrits en Python, il est toutefois possible d’écrire des inventaires dynamiques dans n'importe quel langage en respectant quelques contraintes décrites dans la documentation.

Ces scripts permettent ainsi d’interroger facilement des cloud provider pour obtenir l’ensemble des instances sur lesquelles nous allons jouer le code Ansible. Ces scripts possèdent toutefois des inconvénients : ils ne sont pas liés au code du produit Ansible et possèdent donc un cycle de vie indépendant de celui-ci. Il est compliqué de suivre les changements apportés aux inventaires dynamiques et de suivre un versionning de ceux-ci.

Pour répondre à cette problématique, Ansible a décidé de rapatrier les inventaires dynamiques les plus utilisés au sein de son code et ainsi permettre le versionning des inventaires en même temps qu’Ansible. De plus, ce changement permet de ne plus télécharger de script supplémentaire au sein de notre dépôt de code. Ces inventaires présents directement dans le code Ansible sont appelés les Inventory Plugins. Ces plugins permettent de mettre au propre et de manière native, l’interrogation de Cloud Provider pour la création d’un inventaire Ansible.

Nous allons maintenant voir comment utiliser ces plugins afin d’interroger AWS pour obtenir la liste des instances a interrogé avec Ansible.

Utiliser les plugins

Prérequis

Avant de commencer, assurez-vous d’avoir une version d’Ansible qui supporte les Inventory Plugins. Les extraits de code utilisés dans cet article ont été testés avec la version 2.7.8 qui est la dernière version publiée au jour d’écriture de l’article. Les plugins possèdent chacun des dépendances envers des libs Python qui sont donc à télécharger avant leur utilisation. Dans cet article, nous utilisons le plugin aws_ec2 qui nous précise dans la documentation que l’utilisation de ce plugin nécessite l’installation de library python. Nous devons donc installer les dépendances Python boto3 et botocore avec la commande suivante, par exemple :

$ pip install boto3 botocore

Quick Start

Pour utiliser un Inventory Plugin dans votre dépôt de code, il suffit d’ajouter un fichier avec le nommage spécifique au plugin à utiliser, ainsi que la configuration relative au plugin. Par exemple, pour utiliser le plugin aws_ec2, il faut ajouter le fichier aws_ec2.yml suivant :

---
plugin: aws_ec2

Pour tester que votre inventaire fonctionne, vous pouvez utiliser la commande :

$ ansible-inventory -i aws_ec2.yml --graph
@all:
  |--@aws_ec2:
  |  |--ec2-18-202-225-149.eu-west-1.compute.amazonaws.com
  |  |--ec2-52-47-141-184.eu-west-3.compute.amazonaws.com
  |  |--ip-172-16-0-8.eu-west-1.compute.internal
  |--@ungrouped:

On voit ici que notre inventaire est constitué du groupe all et de deux sous-groupes de all :

  • aws_ec2 : le groupe par défaut du plugin aws_ec2 et qui contient toutes les instances trouvées par le plugin
  • ungrouped : qui contient les machines n’appartenant à aucun autre sous groupe de all. Dans le cas du plugin aws que nous utilisons les machines appartiennent toute au moins au groupe aws_ec2. Ce groupe est donc vide ici, mais ce n’est pas le cas pour d’autres plugins.

Le fichier en question aurait pu être nommé autrement, mais doit respecter la règle de nommage suivante : terminer par aws_ec2.yml ou aws_ec2.yaml. Vous pouvez donc créer des inventaires pour chacun de vos besoins : production_aws_ec2.yml, staging_aws_ec2.yml ou encore all_aws_ec2.yml.

Vous avez maintenant la configuration minimale pour utiliser votre plugin. Nous allons maintenant voir comment filtrer les hôtes récupérés et comment créer des groupes pour organiser les instances suivant des caractéristiques communes.

Comment filtrer et grouper les hôtes

Prenons l’exemple suivant : je possède beaucoup d’instances qui tournent sur mon compte AWS. Ces instances tournent dans plusieurs régions et appartiennent à des équipes différentes. Pour les différencier, les instances possèdent toutes les tags suivants :

  • Projet : Nom du projet de l’instance
  • Environnement : Environnement de l’instance
  • Role : Rôle fonctionnel de l’instance, Proxy par exemple

Maintenant, je souhaite que mon inventaire ne récupère que les instances possédant les traits suivants :

  • Dans la région eu-west-1
  • Avec les tags :
    • Projet : OCTO
    • Environnement : Production

Pour cela, nous allons utiliser les paramètres ‘regions’ et ‘filter’ du plugin aws_ec2 pour pouvoir sélectionner les instances qui nous intéressent. Le fichier de configuration du plugin va donc contenir les informations suivantes :

---
plugin: aws_ec2

# Filtres sur la région et les tags voulus
regions:
  - eu-west-1
filters:
  tags:Projet: OCTO
  tags:Environment: Production

Maintenant que nous avons l’ensemble des instances de notre environnement, nous allons créer des groupes Ansible qui vont nous permettre d’organiser les instances en fonction de leur rôle. Pour cela, nous allons utiliser le paramètre ‘groups’ qui va assigner les hôtes à un groupe en fonction d’une condition booléenne. Si la condition est vraie, l’instance est alors ajoutée au groupe. Nous allons donc nous servir du filtre précédent pour ajouter toutes les instances dans un groupe ‘production’, et créer un groupe ‘instance_proxy‘ pour toutes les instances qui possèdent le tag Role valant proxy.

...

# Grouper les instances
groups:
  production: true
  instance_proxy: "tags.Role == 'Proxy'"

Cette méthode est très pratique pour nommer les groupes comme on le souhaite, mais aussi pour grouper des instances selon des critères plus complexes. Par exemple, il est possible de grouper les instances qui portent un tag spécifique et qui tournent sur une architecture donnée.

my_custom_named: "tags.Role == 'my_tag' and architecture == 'x86_64'"

Cette solution supporte cependant assez mal la mise à l’échelle. Si on veut rajouter un groupe pour de nouvelles instances, il va falloir ajouter à l’inventaire ce nouveau groupe pour qu’il soit pris en compte. Nous allons donc voir comment résoudre ce problème en utilisant les informations fournies par Ansible. Pour ça nous allons utiliser le paramètre ‘keyed_groups’ du plugin aws_ec2. Ce paramètre va permettre de créer des groupes en fonction de la valeur d’une variable. Les instances dont la variable vaut la même valeur se retrouvent dans le même groupe. En utilisant ce paramètre, créons des groupes de instances en fonction du tag Role, afin de générer, pour chaque valeur de ce tag, un groupe Ansible :

...

# Grouper les instances par Role
keyed_groups:
 - key: tags.Role
   separator: ''
   prefix: ''

Les groupes créés auront un nom construit en fonction des trois champs ci-dessus, sous la forme <prefix><separator><valeur du tag Role>. On peut donc modifier le nom des groupes facilement pour donner plus de contexte à ceux-ci. Avec l’exemple précédent on obtient l’inventaire suivant :

$ ansible-inventory -i aws_ec2.yml --graph
@all:
  |--@Proxy:
  |  |--ec2-18-202-225-149.eu-west-1.compute.amazonaws.com
  |--@WebServer:
  |  |--ec2-52-47-141-184.eu-west-3.compute.amazonaws.com
  |--@Backend:
  |  |--ip-172-16-0-8.eu-west-1.compute.internal

En changeant les valeurs de prefix à ‘Role’ et separator à ‘-’ nous aurions ainsi les groupes Role-Proxy, Role-WebServer et Role-Backend.

Au final, au travers d’AWS, nous avons dans un premier temps récupéré l’intégralité des instances de notre compte AWS. Puis nous avons filtré les instances que nous voulions configurer avec Ansible. Enfin, nous avons organisé les instances de manière automatique dans des groupes Ansible grâce à leurs tags. Cette classification des instances se base principalement sur les tags que portent les instances. Il est donc important d’adopter une stratégie de tagging permettant d’effectuer ce regroupement de manière efficace. La manière la plus simple et la plus rapide est de positionner un tag ‘Ansible_Group’ sur les instances pour définir directement le groupe auquel elles appartiennent.

Nous avons pu grouper nos instances grâce au template suivant :

---
plugin: aws_ec2

# Filtres sur la région et les tags voulus
regions:
  - eu-west-1
filters:
  tags:Projet: OCTO
  tags:Environnement: Production

# Grouper les instances
groups:
  production: true
  instance_proxy: "tags.Role == 'Proxy'"

# Grouper les instances par Role
keyed_groups:
 - key: tags.Role
   separator: ''
   prefix: ''

Inventory Plugins le new dynamique

En définitive, les Inventory Plugins d’Ansible permettent de créer facilement des inventaires Ansible que l’on va pouvoir personnaliser à nos besoins. Il est facile de récupérer un inventaire à partir d’un cloud provider, c’était déjà le cas avec les inventaires dynamiques, c’est devenu intégré dans Ansible avec les plugins. Il est du coup assez simple de remplacer les inventaires dynamiques par ces plugins. De plus, les capacités de filtrages permettent d’avoir un inventaire plus petit, ce que ne permettent pas les inventaires dynamiques.

Tous les plugins ne possèdent cependant pas tous les mêmes paramètres pour leur configuration. Par exemple, le paramètre ‘groups’ du plugin aws_ec2 correspond au paramètre ‘conditional_groups’ dans le plugin azure_rm_._ De plus, la totalité des inventaires dynamiques proposés par la communauté n’est pas disponible sous la forme d’Inventory Plugins. Pour connaître la liste complète des plugins que vous pouvez utiliser ainsi que la liste des paramètres à appliquer à chacun d’eux, n’hésitez pas à consulter la documentation à ce sujet.