Aller au contenu
Infrastructure as Code medium

Précédence des variables Ansible : les 22 niveaux officiels (RHCE EX294)

14 min de lecture

Logo Ansible

Quand la même variable est définie à plusieurs endroits, Ansible applique une règle de précédence stricte sur 22 niveaux. Connaître cet ordre vous évite des heures de debug : non, votre group_vars/all.yml ne peut pas écraser un --extra-vars. Oui, vars/main.yml d’un rôle gagne sur vars: du play. Cette page liste les 22 niveaux officiels, du plus faible (role defaults) au plus fort (--extra-vars), avec des règles pratiques pour ne pas se tromper. Objectif explicite RHCE EX294.

C’est une page de référence — on n’apprend pas à coder en la lisant, on revient la consulter quand un comportement vous surprend.

  • L’ordre exact des 22 niveaux de précédence Ansible (du plus faible au plus fort)
  • Le regroupement par catégorie : defaults / group_vars / host_vars / play / role / task / extra
  • Les 3 règles simples qui couvrent 95 % des cas pratiques
  • --extra-vars est toujours prioritaire sur tout
  • Comment diagnostiquer quel niveau a gagné quand une variable a une valeur inattendue

Du plus faible (1) au plus fort (22) :

NiveauSourceNotes
1Command-line values (-u, -c…)Pas vraiment des variables
2roles/<role>/defaults/main.ymlDefaults d’un rôle (override naturel)
3inventory file group varsSection [group:vars] d’un inventaire INI
4inventory group_vars/allÀ côté de l’inventaire
5playbook group_vars/allÀ côté du playbook
6inventory group_vars/<group>À côté de l’inventaire, par groupe
7playbook group_vars/<group>À côté du playbook, par groupe
8inventory file host varsSection [host:vars] d’un inventaire INI
9inventory host_vars/<host>À côté de l’inventaire
10playbook host_vars/<host>À côté du playbook
11host facts / cached set_factsFacts gathered + set_fact avec cacheable: true
12play vars:Bloc vars: au niveau du play
13play vars_prompt:Variables saisies interactivement
14play vars_files:Fichiers YAML chargés par le play
15roles/<role>/vars/main.ymlVars du rôle (gagne sur le play !)
16block varsVars sur un block: (limité aux tâches du block)
17task varsVars sur une tâche (limitées à cette tâche)
18include_varsModule qui charge un fichier au runtime
19set_fact / registerVariables créées en cours d’exécution
20role (and include_role) paramsParams passés à un rôle via roles: - { role: x, var: y }
21include paramsParams passés via include_tasks/include_role
22--extra-varsLe plus fort — gagne sur tout
Fenêtre de terminal
ansible-playbook site.yml --extra-vars "service_name=production-api"

Aucun vars:, vars_files:, group_vars/, host_vars/, set_fact: ou vars/main.yml ne peut écraser ça. C’est le niveau 22.

Implication : --extra-vars est l’outil de prédilection en CI/CD pour pousser un tag de release ou un environnement au runtime, sans modifier le code.

Règle 2 — Plus c’est local, plus c’est prioritaire

Section intitulée « Règle 2 — Plus c’est local, plus c’est prioritaire »

L’intuition naturelle marche : une variable définie à proximité de la tâche gagne sur une variable définie plus loin :

host_vars/<host> > group_vars/<group> > group_vars/all > defaults
↑ très spécifique ↑ très générique
task vars > block vars > play vars > vars_files > group_vars
↑ ultra-local ↑ partagé

Règle 3 — vars/main.yml d’un rôle gagne sur vars: du play

Section intitulée « Règle 3 — vars/main.yml d’un rôle gagne sur vars: du play »

Piège classique : un rôle pose vars/main.yml (niveau 15) qui écrase vos vars: du play (niveau 12). Conséquence : si vous voulez paramétrer un rôle depuis l’extérieur, utilisez :

  • defaults/main.yml du rôle (niveau 2) — peut être overridé naturellement par le caller
  • role params (niveau 20) : roles: - { role: nginx, nginx_port: 8080 }
  • --extra-vars (niveau 22)
# Pas ça : impossible à overrider naturellement depuis le play
# roles/nginx/vars/main.yml :
nginx_port: 80 # ← niveau 15, écrase vars: du play
# Préférer : defaults pour permettre l'override
# roles/nginx/defaults/main.yml :
nginx_port: 80 # ← niveau 2, le caller peut écraser facilement

Cas pratique — 3 niveaux qui se court-circuitent

Section intitulée « Cas pratique — 3 niveaux qui se court-circuitent »

Reprenons l’exemple validé sur le lab 15-ecrire-code-precedence-variables :

# group_vars/dbservers.yml ← niveau 6 ou 7
priority_test: "from_group_vars_dbservers"
# group_vars/all.yml ← niveau 4 ou 5
priority_test: "from_group_vars_all"
# playbook.yml
- name: Test precedence
hosts: db1.lab
vars:
priority_test: "from_play_vars" # ← niveau 12
tasks:
- debug:
msg: "priority_test = {{ priority_test }}"

Sans --extra-vars :

"msg": "priority_test = from_play_vars"

vars: du play (12) gagne sur group_vars/dbservers (6/7) qui gagne sur group_vars/all (4/5).

Avec --extra-vars "priority_test=from_extra_vars" (niveau 22) :

"msg": "priority_test = from_extra_vars"

--extra-vars écrase tout.

Quand une variable a une valeur inattendue, deux outils :

Affiche les variables résolues pour un hôte donné, en montrant l’origine (group_vars, host_vars) :

Fenêtre de terminal
ansible-inventory --host db1.lab

Ne montre pas les vars: du play ni les set_fact: (qui sont dynamiques), mais c’est suffisant pour vérifier group_vars/ et host_vars/.

- name: Debug — voir toutes les sources de la variable
ansible.builtin.debug:
var: priority_test
- name: Debug — voir la valeur réellement utilisée
ansible.builtin.debug:
msg: "priority_test = {{ priority_test }}"

Ajoutez ce duo en haut de votre play quand vous chassez un bug de précédence. Vous voyez immédiatement la valeur active.

Pattern 1 — defaults/main.yml pour permettre l’override

Section intitulée « Pattern 1 — defaults/main.yml pour permettre l’override »

Dans un rôle, toujours mettre les valeurs paramétrables dans defaults/main.yml (niveau 2) :

roles/nginx/defaults/main.yml
nginx_port: 80
nginx_workers: 4
nginx_user: nginx

Le caller peut alors les écraser via vars:, --extra-vars, ou role params.

Pattern 2 — vars/main.yml pour les constantes du rôle

Section intitulée « Pattern 2 — vars/main.yml pour les constantes du rôle »

Réservez vars/main.yml (niveau 15) aux constantes immuables que le caller ne doit pas pouvoir changer :

roles/nginx/vars/main.yml
# Constantes : pas paramétrables par le caller
nginx_pid_file: /var/run/nginx.pid
nginx_log_dir: /var/log/nginx

Pattern 3 — group_vars/<env>.yml pour les overrides d’environnement

Section intitulée « Pattern 3 — group_vars/<env>.yml pour les overrides d’environnement »

Structure type d’un projet multi-environnement :

inventory/
├── prod.yml
├── staging.yml
└── group_vars/
├── all.yml # variables partagées (niveau 4)
├── webservers.yml # variables groupe (niveau 6)
├── prod.yml # variables environnement prod (niveau 6)
└── staging.yml # variables environnement staging (niveau 6)

Lancement :

Fenêtre de terminal
ansible-playbook site.yml -i inventory/prod.yml

group_vars/prod.yml charge automatiquement les variables prod, qui peuvent écraser all.yml.

Un job de CI qui déploie une version :

.gitlab-ci.yml
deploy:
script:
- ansible-playbook site.yml
-i inventory/prod.yml
--extra-vars "release_tag=$CI_COMMIT_TAG"

Aucune variable du repo ne peut écraser release_tag — c’est garanti par le niveau 22.

SymptômeCauseFix
--extra-vars ignoréMauvais format CLIFormat correct : --extra-vars "k=v k2=v2"
group_vars/ introuvableDoit être à côté de l’inventaire OU du playbookVérifier les deux emplacements
Variable d’un rôle non-overridableC’est dans vars/main.yml (niveau 15)Déplacer dans defaults/main.yml (niveau 2)
set_fact perdu entre runsSans cacheable: true, set_fact est éphémèreAjouter cacheable: true (mais attention : devient persistent !)
host_vars/ ne gagne pas sur group_vars/Mauvais nom de fichier (host_vars/web1 vs host_vars/web1.lab)Le nom doit matcher exactement inventory_hostname
  • 22 niveaux officiels Ansible — du plus faible (role defaults) au plus fort (--extra-vars).
  • 3 règles pratiques couvrent 95 % des cas : --extra-vars gagne sur tout ; plus c’est local, plus c’est prioritaire ; vars/main.yml d’un rôle écrase vars: du play.
  • defaults/main.yml d’un rôle = paramétrable ; vars/main.yml = constante.
  • --extra-vars est l’outil CI/CD par excellence (niveau 22 inattaquable).
  • En cas de surprise, ansible-inventory --host <h> + debug: var=.

Cette page a un lab d’accompagnement : labs/ecrire-code/precedence-variables/ dans stephrobert/ansible-training. Il contient un README.md guidé, un Makefile (make verify lance les tests), et un challenge final auto-évalué : valider que —extra-vars (niveau 22) écrase vars: du play et vars_files:.

Une fois le lab provisionné :

Fenêtre de terminal
cd ~/Projets/ansible-training/labs/ecrire-code/precedence-variables/
cat README.md # tuto pas à pas
cat challenge/README.md # consigne du challenge final
pytest -v challenge/tests/ # lancer les tests testinfra

Si les tests passent, vous maîtrisez les concepts couverts dans ce guide. En cas de blocage, docs/troubleshooting.md à la racine du repo couvre les pièges fréquents (rate-limit SSH, clé absente, collection manquante).

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