
Un playbook est une liste ordonnée de plays, chaque play ciblant un groupe d’hôtes avec une séquence de tâches précise. Cette page décortique l’anatomie complète d’un play — au-delà du hosts: + tasks: minimal — et explique l’ordre d’exécution exact des sections (pre_tasks → roles → tasks → post_tasks → handlers). Comprendre cet ordre est essentiel pour structurer correctement vos playbooks et éviter les surprises sur les handlers déclenchés trop tôt ou trop tard.
Cette page se concentre sur l’anatomie. Les mots-clés de parallélisme (serial:, strategy:, max_fail_percentage:) ont leur page dédiée — voir Parallélisme et stratégies.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- L’anatomie complète d’un play et ses mots-clés principaux ;
- L’ordre d’exécution strict :
gather_facts→pre_tasks→roles→tasks→post_tasks→handlers; - Comment enchaîner plusieurs plays dans un même playbook ;
- La différence entre
environment:au niveau play, task et bloc ; - Le pattern
meta: flush_handlerspour forcer les handlers entre deux sections.
Anatomie d’un play complet
Section intitulée « Anatomie d’un play complet »Voici un play qui utilise la majorité des mots-clés disponibles :
---- name: Déployer nginx avec rolling update hosts: webservers become: true gather_facts: true
vars: nginx_version: "1.26.1" nginx_workers: 4
vars_files: - vars/secrets.yml
environment: PATH: "/usr/local/bin:{{ ansible_env.PATH }}" TZ: Europe/Paris
pre_tasks: - name: Drainer le load-balancer ansible.builtin.debug: msg: "Drainer {{ inventory_hostname }} du LB"
roles: - role: nginx vars: nginx_port: 80
tasks: - name: Vérifier que nginx répond ansible.builtin.uri: url: "http://{{ inventory_hostname }}/health" status_code: 200
post_tasks: - name: Réintégrer dans le load-balancer ansible.builtin.debug: msg: "Réintégrer {{ inventory_hostname }} dans le LB"
handlers: - name: Recharger nginx ansible.builtin.systemd: name: nginx state: reloadedChaque mot-clé a un rôle précis. Voyons-les un par un.
Les mots-clés essentiels
Section intitulée « Les mots-clés essentiels »name: (obligatoire)
Section intitulée « name: (obligatoire) »Description humaine du play, affichée dans le PLAY RECAP. Doit décrire l’objectif business, pas la liste des modules.
hosts: (obligatoire)
Section intitulée « hosts: (obligatoire) »Pattern d’hôtes ciblé. Exemples : all, webservers, webservers:!web1, web*:&rhce_lab.
become: et become_user:
Section intitulée « become: et become_user: »become: true élève en root via sudo. become_user: postgres exécute en tant qu’utilisateur dédié (utile pour pg_* commands). Peut être mis au niveau du play, du block, ou de la task.
gather_facts: et gather_subset:
Section intitulée « gather_facts: et gather_subset: »gather_facts: true (défaut) lance le module setup au début et expose ansible_facts.*. Mettre false pour gagner quelques secondes si vous savez ne pas utiliser de facts. gather_subset: '!all,network' restreint à un sous-ensemble (gain de perf sur fleets très grandes).
vars: et vars_files:
Section intitulée « vars: et vars_files: »vars: injecte des variables locales au play. vars_files: charge des fichiers YAML externes (utile pour les secrets vars_files: - vars/secrets.yml chiffrés Vault).
environment:
Section intitulée « environment: »Injecte des variables d’environnement dans le shell qui exécute les modules. Utile pour http_proxy, PATH, LANG. Peut être posé au niveau play, block, ou task — la valeur la plus locale gagne.
environment: HTTP_PROXY: http://proxy.example.com:3128 LANG: en_US.UTF-8Les sections : pre_tasks, tasks, post_tasks, handlers, roles
Section intitulée « Les sections : pre_tasks, tasks, post_tasks, handlers, roles »Un play exécute ses sections dans cet ordre strict :
1. gather_facts (si true)2. pre_tasks ← tâches AVANT les rôles3. handlers déclenchés par les pre_tasks4. roles ← rôles importés5. tasks ← tâches inline6. handlers déclenchés par les tasks/roles7. post_tasks ← tâches APRÈS le reste8. handlers déclenchés par les post_tasksLes handlers sont déclenchés à la fin de chaque section qui les a notifiés — pas à la toute fin du play. Conséquence : si vous redémarrez nginx via un handler dans tasks:, le post_tasks: voit déjà le service redémarré.
pre_tasks:
Section intitulée « pre_tasks: »Tâches exécutées avant les rôles. Cas typiques :
- Drainer un load-balancer avant de toucher aux serveurs ;
- Snapshotter une base de données ;
- Vérifier un prérequis externe (DNS, certificat, accès réseau).
Le cœur du play. Tâches inline qui s’exécutent après les rôles.
post_tasks:
Section intitulée « post_tasks: »Tâches exécutées après tout le reste. Cas typiques :
- Réintégrer dans le load-balancer ;
- Notifier Slack/Teams/PagerDuty ;
- Écrire un journal de déploiement dans une base.
Liste de rôles à importer. Voir la section dédiée Rôles (à venir).
handlers:
Section intitulée « handlers: »Tâches réactives qui ne s’exécutent que si elles sont notifiées par une autre tâche via notify:. Voir la page dédiée Handlers.
Plusieurs plays dans un même playbook
Section intitulée « Plusieurs plays dans un même playbook »Un playbook YAML peut contenir plusieurs plays — exécutés séquentiellement :
---- name: Configurer la base de données hosts: dbservers become: true tasks: - name: Installer PostgreSQL ansible.builtin.dnf: name: postgresql-server state: present
- name: Déployer l'application hosts: webservers become: true tasks: - name: Installer nginx ansible.builtin.dnf: name: nginx state: presentLe second play ne démarre que si le premier réussit sur ses hôtes (sauf si le premier hôte a unreachable=true, le play continue par défaut sur les autres).
meta: flush_handlers — forcer les handlers
Section intitulée « meta: flush_handlers — forcer les handlers »Par défaut, les handlers déclenchés dans pre_tasks: ou tasks: ne tournent qu’à la fin de leur section. Pour les forcer à s’exécuter immédiatement (par exemple avant un smoke test), utiliser :
tasks: - name: Modifier la conf nginx ansible.builtin.copy: dest: /etc/nginx/conf.d/site.conf content: "..." notify: Recharger nginx
- name: Forcer le reload avant la suite ansible.builtin.meta: flush_handlers
- name: Smoke test ansible.builtin.uri: url: http://localhost status_code: 200Sans meta: flush_handlers, le smoke test tournerait avant le reload — donc sur l’ancienne config. Le pattern est essentiel dès que vous avez besoin de tester l’effet d’un handler dans la même section.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
| Handlers exécutés trop tard | Vous attendiez qu’ils tournent avant post_tasks | Forcer le déclenchement avec meta: flush_handlers à la fin de tasks: |
pre_tasks lance des handlers… mais ils tournent à la fin | C’est le comportement standard | Ajouter - meta: flush_handlers après les pre_tasks: |
environment: ne s’applique pas | La var est posée sur le play mais surchargée au niveau task | La règle : la var la plus locale gagne. Vérifier les niveaux play/block/task |
| Plusieurs plays mais le second ne démarre pas | Le premier a marqué tous les hôtes en failed ou unreachable | Vérifier le PLAY RECAP, ajouter ignore_errors: true si pertinent |
À retenir
Section intitulée « À retenir »- Un play déclare
hosts:, exécutepre_tasks→roles→tasks→post_tasks, avec handlers intercalés à chaque section qui les notifie. gather_facts: false+gather_subset:sont les leviers de performance sur grandes fleets.environment:injecte des variables d’environnement avec règle “le plus local gagne” (play < block < task).meta: flush_handlersforce les handlers à tourner immédiatement, sans attendre la fin de la section.- Pour le parallélisme (
serial:,strategy:,max_fail_percentage:), voir Parallélisme et stratégies.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/plays-et-tasks/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : reproduire le pattern pre_tasks + tasks + post_tasks + handlers sur db1.lab avec httpd.
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/plays-et-tasks/
cat README.md # tuto pas à pascat challenge/README.md # consigne du challenge finalpytest -v challenge/tests/ # lancer les tests testinfraSi les tests passent, vous maîtrisez les concepts couverts dans ce guide. En
cas de blocage, docs/troubleshooting.md
à la racine du repo couvre les pièges fréquents (rate-limit SSH, clé absente,
collection manquante).