Aller au contenu
Infrastructure as Code medium

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

65 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).
- name: Inclure des tâches dynamiquement
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
- name: Installer la base de données
ansible.builtin.import_playbook: playbooks/install_db.yml
- name: Installer les serveurs web
ansible.builtin.import_playbook: playbooks/install_web.yml
- name: Configurer l'application
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:.

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

La différence entre statique et dynamique ne se voit qu'à l'exécution, sur le comportement des tags. Le lab vous fait charger le même fichier de tâches avec import_tasks puis avec include_tasks, boucler sur le second, et comparer ce que --tags et when: déclenchent dans chaque cas. Le contrôle regarde les fichiers posés, donc les tâches réellement jouées, pas la syntaxe écrite.

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