Aller au contenu
English
English
Infrastructure as Code medium

Dépendances entre rôles Ansible : meta/main.yml dependencies

75 min de lecture

Logo Ansible

Un rôle peut dépendre d'autres rôles via meta/main.yml. Avant que tasks/main.yml du rôle s'exécute, les dépendances tournent en cascade. Pattern utile pour : firewall_setup avant webserver, selinux_setup avant httpd. Cette page démontre le pattern, l'ordre exact de chargement, et les anti-patterns à éviter.

  • Déclarer des dépendances dans meta/main.yml.
  • L'ordre exact de chargement (dependencies → tasks → handlers).
  • Passer des variables aux dépendances.
  • allow_duplicates pour ré-exécuter un rôle avec des params différents.
  • Anti-patterns : profondeur excessive, dépendances circulaires.
roles/webserver/meta/main.yml
---
galaxy_info:
...
dependencies:
- role: selinux_setup
vars:
selinux_state: enforcing
- role: firewall_setup
vars:
firewall_zones:
- public

Ordre d'exécution :

  1. selinux_setup (1ère dépendance)
  2. firewall_setup (2ème dépendance)
  3. Puis webserver/tasks/main.yml

Les dépendances tournent avant le rôle qui les déclare.

Le playbook n'appelle qu'un seul rôle, webserver, mais trois rôles s'exécutent. Ansible lit d'abord meta/main.yml, joue chaque dépendance dans l'ordre de déclaration, puis seulement ensuite les tâches du rôle appelant. Le schéma donne cet ordre réel.

Le playbook appelle le rôle webserver, Ansible joue d'abord selinux_setup puis firewall_setup, les deux dépendances déclarées dans webserver/meta/main.yml, avant les tâches de webserver

Si selinux_setup lui-même déclare des dépendances, elles tournent avant lui, récursion en profondeur.

dependencies:
- role: firewall_setup
vars:
firewall_zones:
- public
- dmz
firewall_open_services:
- http
- https

Les variables passées au niveau de la dépendance ont priorité élevée, équivalent au vars: sur un roles: classique. Surchargent les defaults/ du rôle dépendant.

Pas possible directement dans dependencies:, pas de when: au niveau meta.

Workaround : conditionner dans le rôle dépendant lui-même :

roles/firewall_setup/tasks/main.yml
- name: Configurer firewalld
ansible.builtin.systemd_service:
name: firewalld
state: started
when: firewall_enabled | default(true)

Ou utiliser include_role avec when: au lieu de dependencies si c'est conditionnel.

allow_duplicates: true, ré-exécuter avec params différents

Section intitulée « allow_duplicates: true, ré-exécuter avec params différents »

Par défaut, un rôle n'est exécuté qu'UNE FOIS dans un play, même s'il est listé plusieurs fois (déduplication automatique). Pour forcer la ré-exécution :

roles/database/meta/main.yml
allow_duplicates: true

Permet :

roles:
- role: database
vars: { db_name: prod, db_port: 5432 }
- role: database
vars: { db_name: staging, db_port: 5433 } # ← exécuté car allow_duplicates: true

Sans allow_duplicates: true, le second appel serait ignoré.

Les trois motifs qui suivent ne produisent aucune erreur au premier essai : le playbook tourne, et la dette s'installe. Ils tiennent tous à la même confusion, prendre dependencies: pour un mécanisme d'orchestration alors qu'il déclare une relation structurelle. Le remède est le même dans les trois cas, un playbook qui appelle les rôles à plat.

Rien n'empêche techniquement une chaîne de cinq rôles, et c'est bien le problème : elle se construit un rôle à la fois, chacun paraissant raisonnable. Le coût se paie au diagnostic, le jour où il faut retrouver quel niveau a posé telle variable. La forme dépliée ci-dessous dit la même chose et se lit d'un coup d'oeil.

webapp → webserver → tls_config → ca_setup → root_ca_distrib

5 niveaux de profondeur. Debug = horreur. Préférer :

# playbook.yml : orchestrateur
- hosts: all
roles:
- root_ca_distrib
- ca_setup
- tls_config
- webserver
- webapp

À plat. Plus lisible.

A dependencies: [B]
B dependencies: [C]
C dependencies: [A]

Ansible refuse, erreur recursive role dependency. À détecter via ansible-galaxy install -r requirements.yml qui valide le graphe.

Mettre toutes les briques de la stack en dependencies du rôle principal :

roles/webapp/meta/main.yml
dependencies:
- role: nginx
- role: php-fpm
- role: postgresql
- role: redis
- role: certbot

Mauvais : le rôle webapp devient inutilisable seul (toutes les deps sont obligatoires). Préférer un playbook qui orchestre.

Le pattern import_role: ou include_role: au lieu de dependencies:

Section intitulée « Le pattern import_role: ou include_role: au lieu de dependencies: »

Souvent plus propre d'appeler les rôles depuis le playbook plutôt que via dependencies: :

playbook.yml
- hosts: webservers
tasks:
- name: Setup SELinux
ansible.builtin.import_role:
name: selinux_setup
- name: Setup firewall
ansible.builtin.import_role:
name: firewall_setup
- name: Deploy webserver
ansible.builtin.import_role:
name: webserver

Avantages :

  • Visibilité : le playbook montre l'ordre clairement.
  • Conditionnel possible avec include_role + when:.
  • Modulaire : webserver peut être utilisé seul (sans déclencher selinux).

dependencies: reste valable pour des dépendances structurelles (ex : un rôle nginx-tls dépend nécessairement de nginx-base).

Une chaîne de dépendances ne se comprend qu'en la regardant se dérouler. Le lab pose un rôle webserver dont le meta/main.yml déclare selinux_setup et firewall_setup, chacun recevant ses propres variables. Vous vérifiez l'ordre réel d'exécution, puis vous vous heurtez au piège du diamant : un rôle listé deux fois n'est joué qu'une seule fois, sauf à poser allow_duplicates: true.

Ces cinq symptômes partagent un trait : aucun ne provoque d'erreur explicite, à l'exception du cycle. Une dépendance sautée, une variable écrasée ou une condition sans effet se manifestent par un résultat inattendu, pas par un message. La colonne du milieu est donc la plus utile à lire en premier.

La collision de variables est celle qui coûte le plus de temps, parce qu'elle donne un résultat cohérent mais faux. Les variables de rôle vivent dans un espace de noms unique pour tout le play : deux rôles chaînés qui déclarent chacun une variable version ne s'isolent pas l'un de l'autre, la seconde valeur écrase la première et le rôle qui s'exécute ensuite déploie la mauvaise. Le préfixage est la seule parade, nginx_version d'un côté et php_version de l'autre, et c'est aussi ce qu'attend la règle var-naming d'ansible-lint. Un nom générique comme port ou user dans les defaults/ d'un rôle tiers est à ce titre un signal d'alerte à l'audit.

SymptômeCauseFix
recursive role dependencyCycle dans le grapheRefactorer pour casser le cycle
Dépendance ignorée silencieusementDéjà jouée dans le même play (déduplication)allow_duplicates: true si volontaire
Variables des deps en collisionPréfixage absentPréfixer <role>_* dans chaque rôle
Profondeur > 2 niveauxArchitecture mal penséeBouger vers playbook orchestrateur
when: sur dep ignoréPas supporté au niveau metaConditionner dans le rôle dépendant

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • meta/main.yml dependencies: chaîne les rôles avant tasks/main.yml.
  • Ordre : dependencies (récursif) → tasks → handlers.
  • vars: sur dep = priorité haute, surcharge defaults.
  • allow_duplicates: true force la ré-exécution avec params différents.
  • Max 2 niveaux de profondeur, sinon préférer un playbook orchestrateur.
  • import_role/include_role dans le playbook = alternative plus visible.
  • Installer rôles Galaxy : résoudre les rôles déclarés en dépendance, avec une version épinglée pour chacun.
  • Auditer un rôle existant : une dépendance tierce entre dans votre chaîne d'exécution, elle mérite le même examen qu'un rôle adopté directement.
  • RHEL System Roles : une bibliothèque conçue pour être chaînée, utile pour éprouver ces mécanismes sur du code réel.

Ce site vous est utile ?

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

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. 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