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.