Aller au contenu
Infrastructure as Code medium

Structure d'un projet Ansible : layout standard et conventions 2026

9 min de lecture

Logo Ansible

Un projet Ansible bien structuré est lisible, versionnable et passe à l’échelle d’une équipe. À l’inverse, un projet en vrac avec un seul gros playbook.yml à la racine devient ingérable dès qu’on dépasse 10 hôtes ou 3 contributeurs. Cette page pose le layout standard retenu dans la communauté en 2026, explique où vit chaque type de fichier (variables, secrets, modules custom, collections, rôles), et donne les conventions de nommage qui rendent un projet lisible.

Le layout que vous lisez ici est compatible RHCE EX294 et avec l’outil moderne ansible-navigator + Execution Environments. Il s’aligne aussi sur ce qu’attendent les outils tiers : ansible-lint, molecule, ansible-galaxy.

  • Le layout standard d’un projet Ansible et le rôle de chaque dossier ;
  • Où placer les variables : group_vars/, host_vars/, vars/, defaults/, vars_files: ;
  • Comment versionner les dépendances : requirements.yml (collections + rôles) et requirements.txt (Python) ;
  • Quand sortir un rôle d’un playbook et où le placer (roles/, Galaxy, Automation Hub) ;
  • Les conventions de nommage qui évitent les conflits sur une équipe.

Voici le layout que vous trouverez sur la majorité des projets Ansible matures :

  • Répertoiremon-projet/
    • ansible.cfg Config Ansible (forks, become, callback…)
    • requirements.yml Collections + rôles externes
    • requirements.txt Dépendances Python
    • .ansible-lint Règles ansible-lint custom
    • Répertoireinventory/
      • hosts.yml Inventaire principal (YAML)
      • production.yml Inventaire prod (optionnel)
      • staging.yml Inventaire staging (optionnel)
    • Répertoiregroup_vars/
      • all.yml Variables pour tous les hôtes
      • webservers.yml Variables pour le groupe webservers
      • dbservers.yml Variables pour le groupe dbservers
    • Répertoirehost_vars/
      • web1.lab.yml Variables spécifiques à web1.lab
      • db1.lab.yml Variables spécifiques à db1.lab
    • Répertoireroles/
      • Répertoirecommon/ Rôle interne au projet
      • Répertoirenginx/ Rôle interne nginx
    • Répertoirecollections/ Collections téléchargées via ansible-galaxy
    • Répertoireplaybooks/
      • site.yml Playbook racine
      • webservers.yml Playbook spécifique webservers
      • dbservers.yml Playbook spécifique dbservers
    • Répertoirefiles/ Fichiers statiques (clés, config, scripts)
    • Répertoiretemplates/ Templates Jinja2 partagés
    • Répertoirelibrary/ Modules custom (Python)
    • Répertoirefilter_plugins/ Plugins de filtres Jinja2 custom
    • Répertoirelookup_plugins/ Plugins de lookup custom

Ce layout n’est pas obligatoire — c’est une convention qui maximise l’interopérabilité avec les outils. Vous pouvez avoir un projet plus minimal (juste ansible.cfg, inventory/hosts.yml, playbooks/site.yml) ou plus structuré (sous-dossiers d’environnements, namespaces internes).

La config locale au projet d’Ansible. Toujours préférée à ~/.ansible.cfg ou /etc/ansible/ansible.cfg pour qu’un git clone suffise à reproduire l’environnement :

[defaults]
inventory = ./inventory/hosts.yml
private_key_file = ./ssh/id_ed25519
forks = 10
host_key_checking = False
stdout_callback = yaml
gathering = smart
fact_caching = jsonfile
fact_caching_connection = ./.ansible_facts
[privilege_escalation]
become = True
become_method = sudo
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True

Deux fichiers, deux univers :

FichierGèreInstallation
requirements.ymlCollections + rôles Ansible Galaxyansible-galaxy install -r requirements.yml
requirements.txtDépendances Python (pour les modules)pip install -r requirements.txt

Exemple requirements.yml :

---
collections:
- name: ansible.posix
version: "2.1.0"
- name: community.general
version: "11.4.7"
- name: community.libvirt
version: "2.2.0"
roles:
- name: geerlingguy.nginx
version: "3.2.0"

Versions épinglées (version:) pour la reproductibilité — pas ~> 1.0 qui prendrait n’importe quelle 1.x.

L’inventaire centralisé. Format YAML privilégié pour les variables structurées. Plusieurs fichiers possibles : production.yml, staging.yml, dev.yml. Activé via --inventory inventory/production.yml ou la variable inventory = d’ansible.cfg.

L’emplacement officiel des variables Ansiblebien plus propre que de mettre des vars: à l’intérieur d’un playbook ou d’un inventaire :

group_vars/
├── all.yml # Variables partagées par TOUS les hôtes
├── webservers.yml # Variables pour le groupe `webservers`
└── dbservers.yml # Variables pour le groupe `dbservers`
host_vars/
├── web1.lab.yml # Variables spécifiques à web1.lab
└── db1.lab.yml # Variables spécifiques à db1.lab

Ansible charge automatiquement ces fichiers en fonction du nom — pas besoin de vars_files:. Si un hôte appartient à plusieurs groupes, les group_vars/<groupe>.yml sont fusionnés dans l’ordre alphabétique (puis écrasés par host_vars/).

Les rôles internes au projet. Chaque rôle a sa propre arborescence (tasks/, handlers/, templates/, defaults/, vars/, meta/, files/). Cf. la section Rôles (à venir).

Pour les rôles externes (Ansible Galaxy), la convention est de les déclarer dans requirements.yml et de les laisser dans ~/.ansible/roles/ ou collections/ansible_collections/.

Le dossier de téléchargement des collections Galaxy installées avec --collections-path. En général, vous laissez Ansible utiliser le path par défaut (~/.ansible/collections/) et vous ne versionnez pas ce dossier dans Git (gitignored).

Deux écoles :

  • Playbooks à la racine : site.yml, webservers.yml directement à la racine du projet. Simple, court à taper. Convient aux petits projets.
  • Playbooks dans playbooks/ : sépare clairement le code de l’inventaire et des variables. La convention recommandée dès qu’un projet dépasse 5 playbooks.
  • library/ : modules Python custom propres au projet. Ansible les charge automatiquement avant les modules standards.
  • filter_plugins/ : filtres Jinja2 custom.
  • lookup_plugins/ : plugins de lookup custom.
  • callback_plugins/ : plugins de callback (sortie custom).

À utiliser avec parcimonie — pour la plupart des cas, une collection externe existe déjà.

C’est la question la plus fréquente en débutant. Voici la décision rapide :

Type de variableEmplacement
Variable globale (port standard, nom organisation)group_vars/all.yml
Variable propre à un groupegroup_vars/<groupe>.yml
Variable propre à un hôtehost_vars/<hôte>.yml
Variable propre à un rôle (par défaut)roles/<role>/defaults/main.yml
Variable forcée par un rôle (non override)roles/<role>/vars/main.yml
Variable temporaire dans un playvars: du play
Variable extérieure injectée--extra-vars (CLI)
Secretansible-vault (cf. section Sécurité)

La précédence complète (22 niveaux) est l’objet d’une page dédiée — c’est l’un des objectifs explicites de la RHCE EX294.

Sur une équipe, ces conventions évitent les conflits et rendent le code lisible :

  • Hostnames : <rôle><n>.<env>.<domain>web1.prod.example.com, db2.staging.example.com.
  • Groupes : pluriel, en kebab-case — webservers, dbservers, load-balancers.
  • Variables : préfixées par le rôle ou le composant — nginx_port, nginx_workers, pg_version. Évite les collisions entre rôles.
  • Playbooks : verbe d’action ou nom de groupe — deploy-webservers.yml, harden-baseline.yml, site.yml.
  • Tags : descriptifs et orthogonaux — nginx, firewall, monitoring. Évite les tag1, step2.
  • Rôles internes : en snake_case ou kebab-casenginx_lab ou nginx-lab (cohérence sur tout le projet).
SymptômeCauseFix
Variables group_vars/all.yml ignoréesLe fichier est mal placé (ex: dans inventory/group_vars/)Le placer à côté du playbook ou de l’inventaire chargé
requirements.yml non installé sur les machines de l’équipePersonne ne lance ansible-galaxy install -r requirements.ymlIntégrer dans le make bootstrap ou la CI
ansible.cfg du projet ignoréLancement depuis un sous-dossier qui contient son propre ansible.cfgToujours lancer depuis la racine du projet (make aide)
Conflit de variables entre deux rôlesRôles utilisent des variables avec le même nom (port, user)Préfixer les variables par le rôle (nginx_port, pg_user)
Secrets en clair dans host_vars/Variables sensibles non chiffréesChiffrer avec ansible-vault ou utiliser un manager externe (HashiCorp Vault, AWS Secrets Manager)
  • Le layout standard inclut ansible.cfg, inventory/, group_vars/, host_vars/, roles/, collections/, requirements.yml et requirements.txt.
  • group_vars/ et host_vars/ sont l’emplacement officiel des variables — bien plus propre que les vars: inline.
  • requirements.yml versionne les collections et rôles Galaxy ; requirements.txt versionne les dépendances Python.
  • Préfixez les variables par le nom du rôle/composant pour éviter les collisions sur une équipe.
  • Les secrets ne vont jamais en clair — ansible-vault ou un manager externe.
  • Le ansible.cfg local au projet est préféré à la version utilisateur — un git clone doit suffire à reproduire l’environnement.

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