
Ansible offre 5 directives pour découper un playbook en fichiers réutilisables : import_tasks, include_tasks, import_role, include_role, import_playbook. La distinction import_* (static) vs include_* (dynamic) est fondamentale et testée à l’EX294 : elles n’ont pas le même comportement vis-à-vis des tags, conditions, variables runtime, handlers et --list-tasks.
À la fin de cette page, vous saurez choisir la bonne directive selon le cas d’usage (boucle ? conditionnel ? variables runtime ?), comprendre pourquoi import_tasks ne supporte pas loop:, et orchestrer un déploiement multi-fichiers avec import_playbook.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Distinguer
import_*(static, résolu au start) vsinclude_*(dynamic, résolu au runtime). - Choisir la bonne directive selon
loop:,tags:,when:, variables runtime. - Découper un playbook avec
import_taskspour la lisibilité. - Boucler sur un fichier de tâches avec
include_tasks+loop:. - Orchestrer plusieurs plays avec
import_playbook. - Comprendre la propagation des
tags:etwhen:selon la directive.
Prérequis
Section intitulée « Prérequis »- Avoir validé Premier playbook.
- Maîtriser les variables et
loop:.
Tableau de référence — quelle directive utiliser
Section intitulée « Tableau de référence — quelle directive utiliser »| Cas d’usage | Directive | Pourquoi |
|---|---|---|
Découper un playbook en fichiers tasks/*.yml (sans loop) | import_tasks | Static, plus rapide, supporte --list-tasks, propage tags:/when: |
Boucler sur un fichier de tâches (loop: [...]) | include_tasks | Static refuse loop: (variable de boucle inexistante au start) |
| Tagger un bloc entier de tâches incluses | import_tasks + tags: | Le tag se propage automatiquement aux tâches importées |
| Appeler un rôle classiquement | import_role ou directive roles: | Static, équivalent au mot-clé roles: du play |
| Boucler sur un rôle | include_role + loop: | Static refuse loop: |
| Orchestrer plusieurs plays | import_playbook (only) | include_playbook n’existe pas |
| Variable de runtime pas encore connue au start | include_* | Dynamic résout au moment de la tâche |
Règle d’or : par défaut, utiliser import_* (plus rapide, plus lisible avec --list-tasks). Basculer sur include_* uniquement si vous avez besoin de loop: ou d’une variable runtime.
import_tasks vs include_tasks
Section intitulée « import_tasks vs include_tasks »Static (import_tasks) — résolu au démarrage
Section intitulée « Static (import_tasks) — résolu au démarrage »- hosts: db1.lab tasks: - name: Importer le bloc d'install (parsé au start) ansible.builtin.import_tasks: tasks/install.yml tags: [setup] # ← propagé à TOUTES les tâches du fichierComportement :
- Ansible lit
tasks/install.ymlau démarrage du playbook (avant exécution). --list-tasksvoit toutes les tâches importées.- Les tags se propagent à chaque tâche du fichier importé.
- Les conditions
when:se propagent à chaque tâche. - Pas de
loop:possible (la variableitemn’existe pas encore au démarrage).
Dynamic (include_tasks) — résolu au runtime
Section intitulée « Dynamic (include_tasks) — résolu au runtime »- hosts: db1.lab tasks: - name: Inclure dans une boucle (dynamic, résolu au runtime) ansible.builtin.include_tasks: tasks/install.yml loop: [1, 2, 3] # ← supporté par include_tasks vars: marker_path: "/tmp/marker-{{ item }}.txt"Comportement :
- Ansible résout
tasks/install.ymlau moment où la tâche est rencontrée. --list-tasksvoit uniquement la directiveinclude_tasks, pas les tâches internes.- Les tags ne se propagent pas automatiquement aux tâches internes (sauf via
apply:). - Les conditions
when:sont évaluées une seule fois sur leinclude_taskslui-même. loop:supporté — c’est la seule raison principale d’utiliserinclude_*.
🔍 Observation cruciale : la différence visible se manifeste sur les tags et la boucle. Le piège classique : on tague un include_tasks en pensant que ça suffit, mais les tâches internes ne sont pas filtrées par --tags <nom>. Pour qu’un tag s’applique aux tâches internes du include, utiliser apply: { tags: [...] }.
Le piège des tags avec include_tasks
Section intitulée « Le piège des tags avec include_tasks »- hosts: db1.lab tasks: # Cas 1 : import_tasks (tag propagé OK) - ansible.builtin.import_tasks: tasks/setup.yml tags: [config]
# Cas 2 : include_tasks SANS apply: (tag NON propagé) - ansible.builtin.include_tasks: tasks/setup.yml tags: [config] # ← tag UNIQUEMENT sur include_tasks lui-même
# Cas 3 : include_tasks AVEC apply: (tag propagé aux tâches internes) - ansible.builtin.include_tasks: tasks/setup.yml apply: tags: [config] # ← propagé à toutes les tâches internes tags: [config]Lancer avec ansible-playbook --tags config :
- Cas 1 : toutes les tâches du fichier importé tournent. ✅
- Cas 2 : rien ne tourne. Les tâches internes ne sont pas taguées
config. ❌ - Cas 3 : toutes les tâches du fichier inclus tournent. ✅
🔍 Observation : le apply: est la clé pour propager les tags (et autres attributs) à travers un include_*. Source de bug fréquent en CI quand on filtre par tag.
import_role vs include_role
Section intitulée « import_role vs include_role »- hosts: db1.lab tasks: - name: Static — équivalent au mot-clé `roles:` du play ansible.builtin.import_role: name: my_role vars: role_var: value
- name: Dynamic — boucler sur un rôle (impossible avec import) ansible.builtin.include_role: name: my_role loop: [1, 2, 3] vars: role_iter: "{{ item }}"🔍 Observation : include_role permet de boucler sur un rôle ou d’appliquer un rôle conditionnellement au runtime. Usage rare mais puissant. Pour 95 % des cas, utiliser import_role ou directement la directive roles: du play.
import_playbook — orchestrer plusieurs plays
Section intitulée « import_playbook — orchestrer plusieurs plays »---# site.yml — orchestrateur- ansible.builtin.import_playbook: playbooks/install_db.yml- ansible.builtin.import_playbook: playbooks/install_web.yml- ansible.builtin.import_playbook: playbooks/configure_app.yml🔍 Observation : import_playbook s’utilise uniquement au niveau plays (pas dans tasks:). include_playbook n’existe pas. Pattern standard pour découper un gros déploiement en sous-playbooks réutilisables, chacun avec son propre hosts:.
Lab pratique
Section intitulée « Lab pratique »Le lab ecrire-code/import-include (labs/ecrire-code/import-include/) reproduit ce parcours avec un challenge qui combine import_tasks (static) + include_tasks avec loop: (dynamic) et 6 tests pytest.
Pièges classiques
Section intitulée « Pièges classiques »import_tasks+loop:→ erreur de parsing au démarrage. Solution :include_tasks.- Tag sur
include_taskssansapply:→ tag non propagé aux tâches internes. Solution : ajouterapply: { tags: [...] }. include_playbookn’existe pas. Pour orchestrer des plays :import_playbookuniquement.--list-tasksne voit pas les tâches dans uninclude_*. Pour audit complet : utiliserimport_*partout où possible.- FQCN obligatoire en 2026 :
ansible.builtin.import_tasks, pas justeimport_tasks(règlefqcn-builtins).
À retenir
Section intitulée « À retenir »import_*= static, parsé au start. Plus rapide. Tags/when propagés.include_*= dynamic, parsé au runtime. Supporteloop:. Tags/when non propagés (saufapply:).import_playbookexiste,include_playbookn’existe pas.- Boucle sur tâches/rôles →
include_*obligatoire. - Default : utiliser
import_*. Basculer surinclude_*uniquement si boucle ou variable runtime. apply:surinclude_taskspropage tags/become/when aux tâches internes.