Loading search data...

Ansible - Les inventaires dynamiques

Publié le : 29 octobre 2021 | Mis à jour le : 22 janvier 2023

logo

Si vos inventaires Ansible varient au fil du temps, avec des hôtes éteints ou pas en réponse aux demandes de l’entreprise, les solutions d'inventaire statique ne répondront pas à vos besoins. C’est là qu’interviennent les inventaires dynamiques.

Utilisation des plugins d’inventaires dynamiques

Les plugins d’inventaire vont vous permettre de récupérer les machines provisionné par exemple sur les providers AWS, Azure, Gcp, … mais aussi des systèmes de monitoring comme Zabbix, des outils réseau comme Netbox …

Pour cela il suffit de créer un fichier de configuration écrit bien sur en yaml et contenant le nom du plugin à utiliser. Le nom de ce fichier doit se terminer par l’extension .yml ou .yaml.

plugin: amazon.aws.aws_ec2
cache: yes
cache_plugin: ansible.builtin.jsonfile
cache_timeout: 7200
cache_connection: /tmp/aws_inventory
cache_prefix: aws_ec2

Comme vous le voyez ci-dessus pour accélérer la collecte des facts Ansible on peut mettre en place du cache. Ici on utilisera simplement des fichiers json, mais il existe d’autres systèmes de cache, comme redis, memcached, ….

Chaque plugin possède ces variables permettant de trier les machines en groupe. Ici ceux pour les machines EC2 d’AWS:

plugin: amazon.aws.aws_ec2
cache: yes
cache_plugin: ansible.builtin.jsonfile
cache_timeout: 7200
cache_connection: /tmp/aws_inventory
cache_prefix: aws_ec2
regions:
  - us-east-1
  - us-east-2
keyed_groups:
  # add hosts to tag_Name_value groups for each aws_ec2 host's tags.Name variable
  - key: tags.Name
    prefix: tag_Name_
    separator: ""
groups:
  # add hosts to the group development if any of the dictionary's keys or values is the word 'devel'
  development: "'devel' in (tags|list)"
compose:
  # set the ansible_host variable to connect with the private IP address without changing the hostname
  ansible_host: private_ip_address

Pour connaître la liste des plugins d’inventaire il suffit de lancer la commande suivante:

ansible-doc -t inventory -l

advanced_host_list                  Parses a 'host list' with ranges
auto                                Loads and executes an inventory plugin specified in a YAML config
community.docker.docker_containers  Ansible dynamic inventory plugin for Docker containers
community.docker.docker_machine     Docker Machine inventory source
community.docker.docker_swarm       Ansible dynamic inventory plugin for Docker swarm nodes
community.general.cobbler           Cobbler inventory source
community.general.gitlab_runners    Ansible dynamic inventory plugin for GitLab runners
community.general.icinga2           Icinga2 inventory source
community.general.linode            Ansible dynamic inventory plugin for Linode
community.general.lxd               Returns Ansible inventory from lxd host
community.general.nmap              Uses nmap to find hosts to target
community.general.online            Scaleway (previously Online SAS or Online.net) inventory source
community.general.opennebula        OpenNebula inventory source
community.general.proxmox           Proxmox inventory source
community.general.scaleway          Scaleway inventory source
community.general.stackpath_compute StackPath Edge Computing inventory source
community.general.virtualbox        virtualbox inventory source
constructed                         Uses Jinja2 to construct vars and groups based on existing inventory
generator                           Uses Jinja2 to construct hosts and groups from patterns
host_list                           Parses a 'host list' string
ini                                 Uses an Ansible INI file as inventory source
script                              Executes an inventory script that returns JSON
toml                                Uses a specific TOML file as an inventory source
yaml                                Uses a specific YAML file as an inventory source

Vous remarquerez que certains sont désormais chargés avec les collections : community.general, community.docker. Pour obtenir leur documentation :

ansible-doc -t inventory <plugin-name>

Pour utiliser cet inventaire dans vos playbooks il suffit d’ajouter comme d’habitude l’option -i <mon_inventaire.yml>. Vous pouvez aussi le définir dans votre configuration ansible.cfg

Quelques plugins d’inventaires dynamiques :

Il en existe plein d’autres … et même pour les devs comme Vagrant

Mise en oeuvre du plugin libvirt

Il suffit de créer un fichier se nommant livirt.yml et d’y mettre ceci :

plugin: community.libvirt.libvirt
uri: 'qemu:///system'

et dans le fichier de config ansible :

[defaults]
inventory=libvirt.yml
interpreter_python=auto_silent
[inventory]
enable_plugins = community.libvirt.libvirt, auto, host_list, yaml, ini, toml, script

Il faut donc installer la collection community.libvirt et le librairie python :

ansible-galaxy collection install community.libvirt
pip install libvirt-python

Maintenant listons les machines disponibles sur ma VM :

sudo virh list --all
 Id   Name                       State
-------------------------------------------
 1    staticip                   running
 -    build-containers_builder   shut off
 -    test-dyn_default           shut off
 -    test-podman_db             shut off

On retrouve la machine que j’ai provisionné avec Terraform. Que donne la commande ansible-inventory :

ansible-inventory --graph --vars
@all:
  |--@144f4357-30fe-4bf8-9484-6f3e6ff2312b:
  |  |--test-podman_db
  |  |  |--{ansible_connection = community.libvirt.libvirt_qemu}
  |  |  |--{ansible_libvirt_uri = qemu:///system}
  |--@b02ea6c4-8dfa-4fc6-8a38-735325ff9815:
  |  |--test-dyn_default
  |  |  |--{ansible_connection = community.libvirt.libvirt_qemu}
  |  |  |--{ansible_libvirt_uri = qemu:///system}
  |--@f2c2438a-3371-41ab-8afe-b8bb59374527:
  |  |--build-containers_builder
  |  |  |--{ansible_connection = community.libvirt.libvirt_qemu}
  |  |  |--{ansible_libvirt_uri = qemu:///system}
  |--@f845cd23-8848-4ce8-9666-d01d6abc0c41:
  |  |--staticip
  |  |  |--{ansible_connection = community.libvirt.libvirt_qemu}
  |  |  |--{ansible_libvirt_uri = qemu:///system}
  |--@ungrouped:

Vous remarquez la chaîne de connexion, ce n’est pas du ssh !

Si on lançait un module sur la machine staticip :

ansible -m ping staticip

staticip | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3.6"
    },
    "changed": false,
    "ping": "pong"
}

Ça marche !

Mise en oeuvre du plugin Amazon Web Services EC2

Le lien vers le billet dédié à terraform + ansible + AWS

Mise en oeuvre du plugin Google Cloud Platform Compute

Le lien vers le billet dédié à terraform + ansible + GCP

Mise en oeuvre du plugin zabbix_inventory

C’est pratiquement la même chose. Il suffit de créer un fichier se nommant zabbix_inventory.yml et d’y mettre ceci :

plugin: community.zabbix.zabbix_inventory
server_url: https://zabbix.robert.local
login_user: user
login_password: xxxxxxxxxxx
validate_certs: no
add_zabbix_groups: true

Il faut bien sur au préalable créer le user sur votre serveur zabbix et lui donner des droits suffisant pour récupérer les serveurs monitorés.

Dans le fichier de config ansible :

[defaults]
inventory=libvirt.yml
interpreter_python=auto_silent
[inventory]
enable_plugins = community.zabbix.zabbix_inventory, auto, host_list, yaml, ini, toml, script

Il faut installer la collection et le la librairie python :

ansible-galaxy collection install community.zabbix
pip install zabbix-api

Maintenant lançons la commande d’inventaire :

ansible-inventory  --graph --vars
...
  |  |--server1
  |  |  |--{zbx_auto_compress = 1}
  |  |  |--{zbx_available = 1}
  |  |  |--{zbx_description = }
  |  |  |--{zbx_disable_until = 0}
  |  |  |--{zbx_error = }
  |  |  |--{zbx_errors_from = 0}
  |  |  |--{zbx_flags = 0}
  |  |  |--{zbx_host = server1}
...

Les machines remontent bien.

Utilisation de script d’inventaire

Vous pouvez aussi écrire vos propres scripts ou plugin d’inventaires.

Utiliser plusieurs sources d’inventaires

Si vous applications sont hébergées chez différents fournisseurs il est possible de faire appel à plusieurs inventaires dans un même playbook.

On peut simplement utiliser plusieurs options -i :

ansible-playbook exemple.yml -i staging -i production

on peut aussi utiliser un répertoire les regroupant par exemple inventory :

inventory/
  openstack.yml          # configure inventory plugin to get hosts from Openstack cloud
  dynamic-inventory.py   # add additional hosts with dynamic inventory script
  static-inventory       # add static hosts and groups
  group_vars/
    all.yml

Ensuite pour faire appel à tous ces inventaires, il suffit de pointer l’option -i sur ce répertoire.

ansible-playbook exemple.yml -i inventory

Pour forcer leur ordre d’exécution il faut les nommer avec un numéro devant :

inventory/
  01-openstack.yml          # configure inventory plugin to get hosts from Openstack cloud
  02-dynamic-inventory.py   # add additional hosts with dynamic inventory script
  03-static-inventory       # add static hosts
  group_vars/
    all.yml

Attention : Veillez à bien cibler les machines par groupe ou hosts dans vos playbooks, éviter le all vous pourriez faire des choses que vous regretteriez par la suite.

Utiliser group_by pour trier vos inventaires

Une des fonctions d’Ansible très peu utilisée, mais qui pourrait d’améliorer vos playbooks est de les trier pour cibler ce qui doit être exécuté dessus. Pour cela il suffit d’utiliser le module group_by.

---
- name: Search alive hosts
- hosts: all
  connection: local
  gather_facts: no
  tasks:
    - block:
        - name: determine hosts that are up
          wait_for_connection:
            timeout: 5
          vars:
            ansible_connection: ssh
        - name: add devices with connectivity to the "running_hosts" group
          group_by:
            key: "running_hosts"
      rescue:
        - name: add devices with connectivity to the "dead_hosts" group
          group_by:
            key: "dead_hosts"

- name: Get facts on alive hosts
- hosts: running_hosts
  gather_facts: no
  tasks:
    - name: get facts
      setup:
        gather_subset: facter
...

On peut aussi les trier par type d’OS : AIX, Alpine, Altlinux, Archlinux, CentOs, …, Windows

- name: Get facts on alive hosts
- hosts: running_hosts
  gather_facts: no
  tasks:
    - name: get facts
      setup:
        gather_subset: facter

    - name: Classify hosts depending on their OS distribution
      group_by:
        key: os_{{ ansible_facts['distribution'] }}

- name : Centos
- hosts: os_CentOS
  gather_facts: False
  tasks:
    - # tasks for CentOS hosts

- hosts: Windows
  gather_facts: False
  tasks:
    - #  tasks for Windows hosts

Et les actions s’enchaînent avec des actions spécifiques utilsant des variables de groupes. Rappel : il suffit de créer un répertoire group_vars avec des fichiers pour chaque groupe.

---
# file: group_vars/all
var1: titi

---
# file: group_vars/os_CentOS.yml
var2: toto

Utilisation des customs facts

Pour enrichir vos inventaires, vous pouvez créer au moment de leur provisionnement des customs facts, et de les mettre à jour régulièrement.

Pour cela il suffit de créer sur ces machines un répertoire /etc/ansible/facts.d et d’y créer des fichiers avec l’extension .fact :

[general]
function="War"
family="Destruction"

A la prochaine collecte vous devriez les voir apparaître :

"ansible_local": {
  "preferences": {
    "general": {
      "function": "War",
      "family": "Destruction"
    }
  }
}

Que vous pourrez ensuite utiliser comme variable dans vos playbooks:

{{ ansible_local['preferences']['general']['function'] }}

Parmi les utilisations possibles :

  • On peut définir une série de variables permettant de définir les règles de mises à jour, de reboot, … de ces machines.
  • On peut définir des variables permettant d’identifier si la machine fais partie d’un groupe particulier.

Mots clés :

devops tutorials ansible

Si vous avez apprécié cet article de blog, vous pouvez m'encourager à produire plus de contenu en m'offrant un café sur  Ko-Fi. Vous pouvez aussi passer votre prochaine commande sur amazon, sans que cela ne vous coûte plus cher, via  ce lien . Vous pouvez aussi partager le lien sur twitter ou Linkedin via les boutons ci-dessous. Je vous remercie pour votre soutien.

Autres Articles


Commentaires: