Comment rendre Ansible statefull ?
Atelier de mise en pratique pour rendre certaines tâches Ansible statefull
La plupart du temps, Ansible parvient à gérer l’idempotence des tâches standards tels que l’installation de paquets standards (via yum
ou apt
). Néanmoins, dans certains cas, il peut être nécessaire de spécifiquement indiquer à Ansible de ne pas exécuter certaines tâches lorsque celles-ci ont déjà été exécutées par le passé.
Prenons le cas d’une instance dont l’exécution du playbook de configuration est planifiée à chaque démarrage et redémarrage de celle-ci.
Nous allons tenter de répondre à la problématique suivante : “comment s’assurer que tout ou partie de cette configuration ne soit exécutée qu’une seule fois ?” avec pour objectif que cette solution soit la plus générique possible.
1 Présentation d’un cas d’usage
Pour l’article, nous allons nous appuyer sur un cas d’usage et prendre pour exemple l’installation de Node.js
sur une instance Debian.
La documentation fournit par l’éditeur précise les actions suivantes pour l’installation de Node.js
en version v20.17.0
via nvm
sur une instance Linux :
|
|
Si nous traduisons cela en playbook Ansible, nous obtenons le résultat suivant :
|
|
Dans ce playbook, on constate que certaines tâches vont être exécutées à chaque fois (notamment : ansible.builtin.shell
) ; que Node.js
soit déjà installé ou non.
Pour éviter cela, nous disposons de deux solutions :
- Faire un test sur l’existence de la commande
node
- Implémenter la notion d’état
Dans ce cas d’usage, la première solution serait peut-être la plus simple ; néanmoins, elle ne correspond pas à notre contrainte évoquée plus haut d’être la plus générique et reproductible possible. C’est pourquoi nous allons donc plutôt nous orienter sur la deuxième solution.
2 Concept
Pour implémenter cette notion d’état, nous allons nous appuyer sur une notion de base d’Ansible : les facts
et les custom facts
.
Les facts
sont des variables qu’Ansible va récupérer au début de l’exécution d’un playbook ou d’une tâche. C’est ce qui se cache derrière TASK [Gathering Facts]
lors de l’exécution d’un playbook. Durant cette étape, Ansible va charger un ensemble de variables par défaut qui peuvent être utiles lors de l’exécution des tâches Ansible (OS utilisé, version de l’OS, capacité mémoire, etc.).
Pour connaître la liste des variables qui sont récupérées par défaut, je vous invite à consulter la documentation Ansible.
En plus de ces facts
chargés par défaut, Ansible met à disposition les custom facts
. Ceux-ci permettent à l’utilisateur de déterminer des facts
personnalisés de manière temporaire ou pérenne. C’est dans ce deuxième cas d’usage que nous allons les utiliser.
3 Implémentation
3.1 Création d’un fichier d’état
Comme évoqué plus haut, la première étape est d’implémenter la notion d’état grâce aux custom facts
.
Créons donc un custom fact
nodejs
, avec un paramètre spécifiant que Node.js
a été installé ainsi qu’un paramètre spécifiant la date à laquelle il a été installé.
Pour cela, il suffit d’ajouter une tâche ansible.builtin.set_fact
:
|
|
Cependant, ce custom fact
nodejs
nouvellement créé ne sera accessible que durant l’exécution courante et ne sera donc pas interrogeable lors de l’exécution suivante.
Pour le rendre persistant pour les prochaines exécutions, nous allons utiliser un répertoire spécifique d’Ansible : /etc/ansible/facts.d
.
Ce répertoire est scanné à chaque démarrage et l’ensemble des fichiers *.fact
sont chargés en plus des facts
par défaut.
Pour cela, il suffit d’ajouter les deux tâches suivantes :
- Création du répertoire
/etc/ansible/facts.d
(s’il n’existe pas déjà) :
|
|
- Création du fichier
/etc/ansible/facts.d/nodejs.fact
au formatJSON
contenant lecustom fact
précédemment créé :
|
|
Nous disposons maintenant d’une variable ansible_local['nodejs']
qui sera chargé lors de la prochaine exécution d’Ansible qui ciblera ce serveur.
3.2 Prise en compte du custom fact
nodejs
lors de l’exécution
Il suffit maintenant de spécifier à Ansible les tâches que nous ne souhaitons exécuter qu’une seule fois grâce à l’option when
:
|
|
Nous obtenons ainsi le résultat suivant :
|
|
4 Validation
Lors de la première exécution sur un serveur, Ansible va réaliser 9 tâches dont 5 avec changement :
|
|
Lors de la deuxième exécution sur le même serveur, nous obtenons le résultat suivant :
|
|
Les tâches ont donc bien été ignorées du fait de la présence du custom fact
.