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.
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 tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn