Playbooks
Les playbooks sont les points d’entrée d’Ansible. Ce sont ces fichiers que l’on va invoquer avec Ansible pour exécuter des ensembles de tâches.
Ils ont un format spécifique qui va décrire :
- sur quels hôtes de l’inventaire seront appliqué les tâches
- les tâches à exécuter
Structure de base
Section titled “Structure de base”La structure de base obligatoire d’un playbook Ansible est la suivante :
---- name: 'Mon playbook' hosts: - machine1 - groupe1 - …On retrouve les clefs suivantes :
name: Le nom du playbookhosts: La liste des hôtes et/ou groupes de l’inventaire sur lequel va être joué le playbook
Ces informations vont permettre de définir le contexte d’exécution du playbook.
Mots clef
Section titled “Mots clef”Il existe plusieurs mots clefs pour déclencher des exécutions.
On va en voir une partie, sans être exhaustif.
| Clef | Format | Description |
|---|---|---|
tasks |
Array |
Liste de tâches à exécuter |
roles |
Array |
Liste de rôles à exécuter |
handlers |
Array |
Liste de tâches à appeler dans des cas spécifiques |
vars |
Forme libre | Liste de variable qui seront spécifiques au playbook |
pre_tasks |
Array |
Liste de tâches à exécuter avant toutes autre action (tasks, roles ou handlers) |
post_tasks |
Array |
Liste de tâches à exécuter après toutes autre action (tasks, roles ou handlers) |
Vous voyez ici deux notions qui n’ont pas été abordée par le moment :
roles: On y reviendra ultérieurement dans une autre page de documentationhandlers: Ce sont des tâches un peu spécifiques. Elles ont exactement le même format et utilisent les mêmes modules que ceux que vous pouvez utiliser dans vostasksnormales. La différence est qu’elles ne seront appelées qu’à deux conditions :- Uniquement en fin d’exécution du playbook ou sur appel volontaire de la meta
flush_handlers - Uniquement suite à une tâche qui a impliqué une modification sur laquelle a été définie la notion de
notify
- Uniquement en fin d’exécution du playbook ou sur appel volontaire de la meta
Ne vous inquiétez pas, la notion de handlers peut rester flou jusque-là, on y revient dans très peu de temps.
Un playbook basique
Section titled “Un playbook basique”Prenons le cas simple où l’on veut installer le paquet vim sur l’ensemble de nos machines.
On va pour celà créer notre fichier d’inventaire qui va lister l’ensemble des machines, et le fichier de playbook qui
va exécuter les tâches à notre place :
all: hosts: w1.example.org: w2.example.org: d1.example.org: children: webservers: hosts: w1.example.org: w2.example.org:---- name: 'Installation de vim sur l’ensemble des machines' # On indique ici que toutes les machines de l’inventaire sont concernée par le playbook hosts: - all tasks: # On ajoute la tâche qui va permettre l’installation du paquet vim sur les machines - name: 'Installation de vim' # On indique que la tâche doit être joué avec une élévation de privilège become: true # On indique l’utilisateur cible pour l’élévation de privilège. # Cette partie n’est pas obligatoire dans le cas de root, c’est l’utilisateur cible par défaut d’un become become_user: 'root' # On utilise le module Ansible ansible.builtin.package ansible.builtin.package: # On spécifie au module le nom du paquet à installer name: 'vim' # On spécifie au module l’état désiré du paquet state: presentAvec ces fichiers (en ayant adapté l’inventaire à votre environnement), vous pouvez exécuter le playbook pour installer vim sur les machines de votre inventaire :
ansible-playbook -i inventory.yaml basic-playbook.yamlVous devriez obtenir un résultat similaire à ça :
PLAY [Installation de vim sur l’ensemble des machines] *****************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0mok: [d1.example.org][0m
TASK [Installation de vim] *********************************************************************************************ok: [d1.example.org][0mchanged: [w2.example.org][0mchanged: [w1.example.org][0m
PLAY RECAP *************************************************************************************************************w1.example.org : ok=2[0m [0;33mchanged=1[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0d1.example.org : ok=2[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0w2.example.org : ok=2[0m [0;33mchanged=1[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0La première tâche Gathering Facts assure la collecte des facts sur les équipements.
Cette tâche est implicite ce n’est pas vous qui la déclarez, et elle sera toujours la première tâche à être effectuée
lors de l’exécution d’un playbook.
Dans mon cas, la machine d1.example.org avait déjà le paquet vim d’installé, ce qui fait que la tâche d’installation
n’a pas généré de changement et est en status ok.
Pour les autres machines, la tâche d’installation a bien généré un changement (l’installation du paquet), et donc
le status est passé en changed.
Handlers
Section titled “Handlers”Je vous ai parlé dans les Mots clef des handlers. Les handlers sont des tâches un peu particulières parce qu’elles sont considéré comme réutilisables.
Ces tâches ne sont pas exécutées dans le déroulé classique de votre playbook, elle ne seront exécuté que sous deux conditions :
- Si elles ont été notifiée par une autre tâche (j’y reviens juste après)
- Soit en fin de playbook, soit sur appel d’une meta tâche
flush_handlers
L’utilité des handlers se retrouve à plusieurs niveaux :
- L’installation d’un nouveau service pour s’assurer d’un état en fin d’exécution
- Suite à la modification de la configuration d’un service pour s’assurer de correctement relancer le service
Un même handler peut être notifié plusieurs fois par des tâches différentes, il ne sera joué qu’une seule fois.
Notify
Section titled “Notify”Les notifications aux handlers s’effectuent au travers du mot clef notify qui sera à adosser à une tâche standard.
L’effet qu’aura le notify sera d’enregistrer la nécessité d’exécuter un handler.
Il ne sera activé que si une tâche est en état changed. Dans tous les autres cas, la notification n’aura pas lieu
et le handler ne sera pas exécuté.
Example d’utilisation
Section titled “Example d’utilisation”Prenons le cas où vous souhaitez déployer un serveur web.
En premier lieu, vous allez installer les paquets nécessaires. Vous pourrez à ce moment notifier un handler qui va s’assurer que le service apache2 est démarré, et activé au démarrage de la machine.
Le playbook ressemblerait à celà :
---- name: 'Installe et configure apache2' hosts: - webservers tasks: - name: 'Installation du paquet apache2' become: true ansible.builtin.package: name: apache2 state: present - name: 'Redemarre et active apache2' become: true ansible.builtin.systemd_service: name: apache2 state: restarted daemon-reload: true enabled: trueOn veut ensuite modifier le fichier de configuration d’apache2 ce qui nécessitera un redémarrage.
Voici les playbooks avec et sans handlers :
---- name: 'Installe et configure apache2' hosts: - webservers tasks: - name: 'Installation du paquet apache2' become: true ansible.builtin.package: name: apache2 state: present - name: 'Modification de la configuration de apache2' become: true ansible.builtin.template: content: "{{ ansible_managed }}" dest: '/etc/apache2/fake_config.conf' - name: 'Redemarre et active apache2' become: true ansible.builtin.systemd_service: name: apache2 state: restarted daemon-reload: true enabled: true---- name: 'Installe et configure apache2' hosts: - webservers handlers: - name: 'Redemarre et active apache2' become: true ansible.builtin.systemd_service: name: apache2 state: restarted daemon-reload: true enabled: true tasks: - name: 'Installation du paquet apache2' become: true notify: 'Redemarre et active apache2' ansible.builtin.package: name: apache2 state: present - name: 'Modification de la configuration de apache2' become: true notify: 'Redemarre et active apache2' ansible.builtin.template: content: "{{ ansible_managed }}" dest: '/etc/apache2/fake_config.conf'Dans le cas du playbook sans la gestion du handler, Ansible va systématiquement redémarrer apache2 à chaque rejeu. Dans le cas du playbook avec le handler, ce dernier ne sera exécuté qui si apache2 a été installé ou si la configuration a été modifiée pendant l’exécution du playbook.
Celà évite des actions inutiles pendant l’exécution, et surtout ça évite une rupture de service à l’exécution du playbook.
Si vous exécutez le playbook avec ou sans handler une première fois, vous devriez avoir les résultats suivants :
PLAY [Installe et configure apache2] ***********************************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Installation du paquet apache2] **********************************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
TASK [Modification de la configuration de apache2] *********************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
TASK [Redemarre et active apache2] *************************************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
PLAY RECAP *************************************************************************************************************w1.example.org : ok=1[0m [0;33mchanged=3[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0w2.example.org : ok=1[0m [0;33mchanged=3[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0PLAY [Installe et configure apache2] ***********************************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Installation du paquet apache2] **********************************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
TASK [Modification de la configuration de apache2] *********************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
RUNNING HANDLER [Redemarre et active apache2] ***************************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
PLAY RECAP *************************************************************************************************************w1.example.org : ok=1[0m [0;33mchanged=3[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0w2.example.org : ok=1[0m [0;33mchanged=3[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Sur la première exécution, les résultats sont les mêmes, c’est normal vu que les machines n’avaient ni les paquets, ni le fichier que l’on pousse avec ansible.
Si vous le relancez une deuxième fois sans modifications, vous aurez le résultat suivant :
PLAY [Installe et configure apache2] ***********************************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Installation du paquet apache2] **********************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Modification de la configuration de apache2] *********************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Redemarre et active apache2] *************************************************************************************changed: [w2.example.org][0mchanged: [w1.example.org][0m
PLAY RECAP *************************************************************************************************************w1.example.org : ok=3[0m [0;33mchanged=1[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0w2.example.org : ok=3[0m [0;33mchanged=1[0m unreachable=0 failed=0 skipped=0 rescued=0 ignored=0PLAY [Installe et configure apache2] ***********************************************************************************
TASK [Gathering Facts] *************************************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Installation du paquet apache2] **********************************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
TASK [Modification de la configuration de apache2] *********************************************************************ok: [w2.example.org][0mok: [w1.example.org][0m
PLAY RECAP *************************************************************************************************************w1.example.org : ok=3[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0w2.example.org : ok=3[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Ce que l’on constate, c’est que dans le cas où il n’y a pas de handler, le service apache2 est quand même redémarré par Ansible.
Dans le cas où on a mis en place le handler, Ansible n’ayant pas détecté de modification sur la machine, il n’a pas de raison de redémarrer le service apache2, et de fait, le handler n’est pas exécuté.
Forcer l’exécution des handlers
Section titled “Forcer l’exécution des handlers”Lorsque vous écrivez des playbooks long et/ou complexes, il peut s’avérer nécessaire d’exécuter les handlers avant la fin de l’exécution du playbook.
Ansible prévoit une méthode pour forcer l’exécution des handlers en cours d’exécution.
Attention: L’utilisation de cette méthode contraint l’exécution de l’ensemble des handlers qui ont été notifiés. Il est donc nécessaire d’avoir bien conscience de qu’est-ce qui va être joué lors de l’appel.
Pour forcer l’exécution des handlers, le module à appeler est meta :
…- name: 'Exécution forcée des handlers' ansible.builtin.meta: flush_handlers…Personnellement, j’ai tendance à mettre quasi systématiquement une tâche pour forcer l’exécution des handlers à la fin de mes playbooks.
La raison pour laquelle je fais celà, et qu’assez régulièrement, je chaine plusieurs playbooks à la suite dans un même fichier. Le fait d’ajouter une tâche terminale pour forcer l’exécution des handlers m’assure que l’ensemble de ce qui doit être joué dans un playbook est correctement effectué avant de passer au suivant.