Aller au contenu
Infrastructure as Code medium

Import vs Include Ansible : import_tasks, include_tasks, import_role, include_role, import_playbook

10 min de lecture

Logo Ansible

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.

  • Distinguer import_* (static, résolu au start) vs include_* (dynamic, résolu au runtime).
  • Choisir la bonne directive selon loop:, tags:, when:, variables runtime.
  • Découper un playbook avec import_tasks pour la lisibilité.
  • Boucler sur un fichier de tâches avec include_tasks + loop:.
  • Orchestrer plusieurs plays avec import_playbook.
  • Comprendre la propagation des tags: et when: selon la directive.

Tableau de référence — quelle directive utiliser

Section intitulée « Tableau de référence — quelle directive utiliser »
Cas d’usageDirectivePourquoi
Découper un playbook en fichiers tasks/*.yml (sans loop)import_tasksStatic, plus rapide, supporte --list-tasks, propage tags:/when:
Boucler sur un fichier de tâches (loop: [...])include_tasksStatic refuse loop: (variable de boucle inexistante au start)
Tagger un bloc entier de tâches inclusesimport_tasks + tags:Le tag se propage automatiquement aux tâches importées
Appeler un rôle classiquementimport_role ou directive roles:Static, équivalent au mot-clé roles: du play
Boucler sur un rôleinclude_role + loop:Static refuse loop:
Orchestrer plusieurs playsimport_playbook (only)include_playbook n’existe pas
Variable de runtime pas encore connue au startinclude_*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.

- 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 fichier

Comportement :

  • Ansible lit tasks/install.yml au démarrage du playbook (avant exécution).
  • --list-tasks voit 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 variable item n’existe pas encore au démarrage).
- 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.yml au moment où la tâche est rencontrée.
  • --list-tasks voit uniquement la directive include_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 le include_tasks lui-même.
  • loop: supporté — c’est la seule raison principale d’utiliser include_*.

🔍 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: [...] }.

- 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.

- 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.

---
# 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:.

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.

  • import_tasks + loop: → erreur de parsing au démarrage. Solution : include_tasks.
  • Tag sur include_tasks sans apply: → tag non propagé aux tâches internes. Solution : ajouter apply: { tags: [...] }.
  • include_playbook n’existe pas. Pour orchestrer des plays : import_playbook uniquement.
  • --list-tasks ne voit pas les tâches dans un include_*. Pour audit complet : utiliser import_* partout où possible.
  • FQCN obligatoire en 2026 : ansible.builtin.import_tasks, pas juste import_tasks (règle fqcn-builtins).
  • import_* = static, parsé au start. Plus rapide. Tags/when propagés.
  • include_* = dynamic, parsé au runtime. Supporte loop:. Tags/when non propagés (sauf apply:).
  • import_playbook existe, include_playbook n’existe pas.
  • Boucle sur tâches/rôlesinclude_* obligatoire.
  • Default : utiliser import_*. Basculer sur include_* uniquement si boucle ou variable runtime.
  • apply: sur include_tasks propage tags/become/when aux tâches internes.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn