Skip to content

Inventaires

Les inventaires Ansible permettent non seulement de définir les machines qui seront managés par Ansible, mais aussi des groupes fonctionnels ou des variables contextuelles.

Il est possible de configurer les inventaires via deux formats :

  • INI
  • YAML

Personnellement, je préfère les inventaires au format YAML. Je trouve ça bien plus lisible dans le cas où l’inventaire devient volumineux.

Je vous mets un example avec le même inventaire écrit en INI et en YAML :

Base inventory
[all]
machine1
machine2
[web]
machine1
[mysql]
machine2

Personnellement, je n’utilise que le format Ansible car je trouve ce dernier plus simple d’usage dans le cas d’inventaires qui commencent à être assez conséquents.

La toute première notion à comprendre est la notion d’hôtes. Ce sont au sens propre les cibles qui seront managées par Ansible.

Pour donner un exemple de la méthode de déclaration des hôtes, on va créer un inventaire basique avec 4 hôtes :

  • w1.example.org
  • w2.example.org
  • d1.example.org
  • d2.example.org

Le fichier YAML se présentera ainsi comme ça :

Inventaire basique
---
# Clef générique pour l’ensemble de l’inventaire
all:
# Clef permettant de définir l’ensemble des hôtes
hosts:
# Liste des hôtes par leurs FQDN
w1.example.org:
w2.example.org:
d1.example.org:
d2.example.org:

Vous pouvez créer un fichier inventories/inventory.yaml avec le contenu semblable à celui ci-dessus pour tester.

De cette façon, il est possible d’utiliser Ansible soit unitairement sur un hôte ou pour l’ensemble des hôtes via all.

Pour exécuter le module ping sur un hôte spécifique la commande sera la suivante :

Exécution du module ping sur w1.example.org
ansible -m ping -i inventories/inventory.yaml w1.example.org

Pour le même module pour l’ensemble des hôtes :

Exécution du module ping sur l’ensemble de l’inventaire
ansible -m ping -i inventories/inventory.yaml all

Ici pas de complexité donc. Le seul besoin tant que les machines soit enregistrée dans le DNS avec le nom que vous avez fourni dans l’inventaire.

Il est possible dans un inventaire Ansible de structurer des groupes. Cette fonctionnalité est assez libre, car on peut structure des groupes d’hôtes ou des groupes de groupes.

Pour créer des groupes d’hôtes, nous allons repartir de l’inventaire présent dans la Les hôtes avec les mêmes machines.

Imaginons que les machines w1 et w2 sont des machines vouées à être des serveurs web et les machines d1 et d2 sont vouées à être des bases de données.

On peut définir deux groupes webservers et databases tel que suivant :

Ajout des groupes
all:
hosts:
w1.example.org:
w2.example.org:
d1.example.org:
d2.example.org:
# La clef children définit que ce qui sera positionné en dessous seront des groupes
children:
# On définit le groupe webservers
webservers:
# La liste des hôtes qui seront inclus dans ce groupe.
hosts:
w1.example.org:
w2.example.org:
# On définit le groupe databases
databases:
# La liste des hôtes qui seront inclus dans ce groupe.
hosts:
d1.example.org:
d2.example.org:

À cette étape, vous avez deux groupes indépendants dans votre inventaire.

Ces groupes sont utilisables pour l’exécution des modules. À l’instar des commandes précédentes, vous pouvez le vérifier avec la commande :

Exécution module ping sur les hôtes webservers
ansible -m ping -i inventories/inventory.yaml webservers

Dans ce cas précis, seul les équipements du groupe webservers doivent vous répondre.

Il est possible d’inclure des variables dans les inventaires. Ces variables viendront définir certaines configurations qui seront appliquées dans vos tâches et/ou rôles, mais également des informations contextuelles pour vos différents équipements.

Si par exemple vous n’avez pas d’enregistrements DNS défini pour certains de vos équipements, il est tout à fait possible de spécifier l’adresse IP d’un ou plusieurs équipements afin qu’Ansible s’appuie dessus plutôt que sur le DNS pour contacter l’équipement en question.

Cette variable contextuelle est ce que l’on appelle un fact dans la terminologie Ansible. Ce sont des variables qui sont automatiquement définie en fonction du contexte (de l’équipement ou de l’environnement).

Le fact permettant de spécifier l’adresse IP d’un équipement qui sera managé par Ansible est ansible_host.

Si on amende l’inventaire pour spécifier ce fact pour l’ensemble des équipements celà donne le fichier suivant :

Inventaire avec ansible_host
all:
hosts:
w1.example.org:
ansible_host: '10.0.0.10'
w2.example.org:
ansible_host: '10.0.0.11'
d1.example.org:
ansible_host: '10.0.1.10'
d2.example.org:
ansible_host: '10.0.1.10'
children:
webservers:
hosts:
w1.example.org:
w2.example.org:
databases:
hosts:
d1.example.org:
d2.example.org:

Le fait de spécifier le fact ansible_host dans un inventaire induit qu’Ansible ne tentera plus de résolution DNS pour l’hôte en question et se basera sur la valeur spécifiée.

Dans le cas où vous vous retrouvez à avoir des inventaires complexes avec beaucoup de variables et/ou de facts défini à l’intérieur, il devient préférable d’utiliser la méthode recommandée par Ansible pour gérer les variables.

Cette méthode consiste en l’utilisation de deux dossiers ayant des noms particuliers :

  • group_vars : Dossier qui contiendra les variables pour les différents groupes de l’inventaire
  • hosts_vars : Dossier qui contiendra les variables pour l’ensemble des hôtes de l’inventaire.

De mon point de vue ainsi que de par mon usage, le fichier de référence d’inventaire (inventories/inventory.yaml) doit être laissé le plus pur possible. J’entends par là qu’il ne doit contenir que les hôtes (et éventuellement leurs facts ansible_host si besoin) et les groupes. Je trouve que lors de l’utilisation de gros inventaires d’infrastructure celà rends la maintenance et la gestion plus facile d’avoir les variables rangées dans des fichiers en propre.

Prenons l’exemple suivant (c’est un example qui est volontairement abstrait, c’est pour que vous compreniez le fonctionnement des group_vars et des hosts_vars) :

  1. Pour les machines qui seront des serveurs web, on veut spécifier que le dossier qui contiendra le site Web sera dans le dossier /srv/web/site
  2. Pour les machines de base de données, on veut spécifier que le dossier qui contiendra les données sera dans /opt/db
  3. Pour la machine d1.example.org on veut que le moteur de base de donnée soit en version 10.0.1
  4. Pour la machine d2.example.org on veut que le moteur de base de donnée soit en version 11.0.0

Si on stocke toute ces informations dans l’inventaire, on va se retrouver avec l’inventaire suivant :

Inventaire avec les variables
all:
hosts:
w1.example.org:
ansible_host: '10.0.0.10'
w2.example.org:
ansible_host: '10.0.0.11'
d1.example.org:
ansible_host: '10.0.1.10'
db_version: '10.0.1'
d2.example.org:
ansible_host: '10.0.1.10'
db version: '11.0.0'
children:
webservers:
hosts:
w1.example.org:
w2.example.org:
vars:
web_storage: '/srv/web/site'
databases:
hosts:
d1.example.org:
d2.example.org:
vars:
db_storage: '/opt/db'

Je vous laisse imaginer ce que ça peut donner sur un inventaire qui contient plusieurs dixaines de machines avec des applicatifs divers et variés.

L’utilisation des group_vars et des hosts_vars permet de splitter celà facilement.

En terme d’arborescence, celà va donner celà :

  • Directoryinventories/
    • Directorygroup_vars/
      • Directorywebservers/
        • storage.yaml
      • Directorydatabases/
        • storage.yaml
    • Directoryhosts_vars/
      • Directoryd1.example.org/
        • db_version.yaml
      • Directoryd2.example.org/
        • db_version.yaml

Le contenu des fichiers serait le suivant :

group_vars/webserver/storage.yaml
---
web_storage: '/srv/web/site'

L’utilisation de ces dossiers permet beaucoup plus de flexibilité que d’utiliser le fichier principal d’inventaire. Vous pouvez créer autant de fichiers que vous le souhaitez dans chaque dossier, la seule structure imposée se situe directement sous les dossiers group_vars ou hosts_vars car les dossiers ou fichiers qui sont contenus au premier niveau doivent correspondre aux noms des hôtes ou des groupes de votre inventaire.

Le fait que j’utilise des dossiers pour les groupes et les hôtes me permet de splitter mes variables au besoin dans chaque dossier.

Typiquement, dans mon cas d’usage, je vais avoir de façon très régulière avoir pour chaque hôte :

  • Un fichier firewall.yaml qui va définir uniquement les règles de firewall pour la machine
  • Un fichier ntp.yaml qui va définir uniquement les paramètres de configuration du client NTP
  • …

Une commande très pratique pour voir comment est constitué un inventaire afin d’identifier quelles variables touche quel hôte ou quel groupe et pour savoir quel hôte est membre de quel groupe :

ansible-inventory
ansible-inventory -i inventories/inventory.yaml --graph --vars