Aller au contenu
Infrastructure as Code medium

Variables Ansible : déclaration, portées et override par --extra-vars

11 min de lecture

Logo Ansible

Une variable Ansible peut être déclarée à 5 endroits différents — et selon l’endroit, elle est plus ou moins prioritaire. Cette page pose les bases : les 5 emplacements principaux (vars:, vars_files:, --extra-vars, group_vars/, host_vars/), les types simples acceptés (string, integer, float, boolean), et les règles de portée d’une variable du play vers les tâches enfants. La précédence complète (22 niveaux officiels) est l’objet d’une page dédiée — ici on couvre les cas les plus fréquents.

L’exemple central : un playbook qui déclare des variables au niveau play, charge un fichier de variables externe, et accepte un override CLI via --extra-vars. C’est exactement le pattern utilisé en CI/CD pour pousser une variable de release au runtime sans modifier le code.

  • Déclarer une variable via vars: au niveau d’un play
  • Charger un fichier YAML externe via vars_files: (utile pour les secrets Vault)
  • Overrider via --extra-vars depuis la ligne de commande (niveau le plus prioritaire)
  • Comprendre le rôle de group_vars/ et host_vars/ comme emplacements automatiques
  • Reconnaître les types simples : string, integer, float, boolean, null
  • Avoir lu la sous-section Fondations ;
  • Connaître les bases d’un play : hosts:, become:, tasks: (cf. Plays et tasks).

C’est l’emplacement le plus simple : un bloc vars: à l’intérieur d’un play. Les variables sont disponibles dans toutes les tâches du play.

- name: Démo variables play
hosts: web1.lab
become: true
vars:
service_name: "default-service"
service_port: 8000
debug_enabled: false
tasks:
- name: Afficher
ansible.builtin.debug:
msg: "{{ service_name }} sur le port {{ service_port }}"

Convient pour des variables courtes, qui n’ont de sens qu’à l’intérieur du play.

Quand le bloc vars: devient trop long ou contient des secrets (qu’on veut chiffrer avec ansible-vault), on bascule sur des fichiers externes :

- name: Démo vars_files
hosts: web1.lab
become: true
vars_files:
- vars/app.yml
- vars/secrets.yml # chiffré avec ansible-vault
tasks:
- name: Afficher la version
ansible.builtin.debug:
msg: "Version : {{ app_version }}"

vars/app.yml :

---
app_version: "1.0"
app_port: 80

Les variables du fichier sont fusionnées avec les vars: du play. Si une clé existe dans les deux, le vars: du play l’emporte (mais cette nuance varie selon la précédence — cf. page dédiée).

L’emplacement le plus prioritaire (niveau 22) — même au-dessus de vars/main.yml d’un rôle. Permet d’injecter une variable au runtime sans toucher au code :

Fenêtre de terminal
ansible-playbook site.yml --extra-vars "service_name=production-api"

Plusieurs variables :

Fenêtre de terminal
ansible-playbook site.yml \
--extra-vars "service_name=production-api db_max_connections=500"

Depuis un fichier JSON ou YAML :

Fenêtre de terminal
ansible-playbook site.yml --extra-vars "@vars/release.yml"

C’est le pattern par excellence en CI/CD : la pipeline injecte la version, l’environnement, le tag de release.

4. group_vars/ — variables par groupe d’inventaire

Section intitulée « 4. group_vars/ — variables par groupe d’inventaire »

Le dossier group_vars/ à côté de l’inventaire ou du playbook est chargé automatiquement :

group_vars/
├── all.yml # variables pour TOUS les hôtes
├── webservers.yml # variables pour le groupe webservers
└── dbservers.yml # variables pour le groupe dbservers

group_vars/webservers.yml :

---
nginx_workers: 4
nginx_port: 80

Sans vars_files:, sans bloc vars:, ces variables sont disponibles dans tout play qui cible le groupe webservers.

Idem mais par hôte :

host_vars/
├── web1.lab.yml # variables propres à web1.lab
└── db1.lab.yml # variables propres à db1.lab

Plus prioritaire que group_vars/ : si une variable est définie dans les deux, host_vars/<hôte>.yml l’emporte.

Cas pratique — précédence vars / vars_files / —extra-vars

Section intitulée « Cas pratique — précédence vars / vars_files / —extra-vars »

Reprenons l’exemple complet du lab. Un playbook qui combine les trois sources, et un --extra-vars qui override sélectivement :

---
- name: Challenge variables-base (precedence vars play vs vars_files vs extra-vars)
hosts: db1.lab
become: true
vars:
service_name: "default-service"
service_port: 8000
vars_files:
- vars/db.yml
tasks:
- name: Poser le fichier marqueur avec toutes les variables résolues
ansible.builtin.copy:
dest: /tmp/challenge-vars.txt
content: |
service_name={{ service_name }}
service_port={{ service_port }}
db_engine={{ db_engine }}
db_max_connections={{ db_max_connections }}
mode: "0644"

Avec vars/db.yml :

---
db_engine: "postgresql"
db_max_connections: 100

Lancement avec override :

Fenêtre de terminal
ansible-playbook site.yml \
--extra-vars "service_name=production-api db_max_connections=500"

Contenu attendu de /tmp/challenge-vars.txt :

service_name=production-api ← écrasé par --extra-vars (niveau 22)
service_port=8000 ← du vars: du play (niveau 4)
db_engine=postgresql ← du vars_files: (niveau 7)
db_max_connections=500 ← écrasé par --extra-vars

--extra-vars gagne sur tout. Le vars: du play et le vars_files: ne sont actifs que pour les variables non surchargées.

YAML 1.2 reconnaît automatiquement les types primitifs sans annotation :

# String
service_name: "production-api"
service_short_name: nginx # OK sans quotes (pas de caractère ambigu)
# Integer
service_port: 8080
max_connections: 100
# Float
timeout_seconds: 30.5
# Boolean (YAML 1.2 strict)
debug_enabled: true
ssl_required: false
# Null
optional_value: ~ # ou : null

Une variable déclarée au niveau play (vars:) est disponible :

  • Dans toutes les tâches (tasks:, pre_tasks:, post_tasks:)
  • Dans les handlers déclenchés par ce play
  • Dans les rôles appelés par ce play (sauf si le rôle redéfinit la variable dans vars/main.yml)
  • Dans les modules d’expression : when:, loop:, register:

Une variable déclarée dans group_vars/all.yml est disponible partout, dans tout play, du moment que l’inventaire est chargé.

Une variable déclarée dans vars/ d’un rôle (roles/<role>/vars/main.yml) est figée pour ce rôle — elle écrase même les vars: du play. À utiliser avec parcimonie : préférez defaults/main.yml (faible précédence, override naturel par le caller).

SymptômeCauseFix
--extra-vars ignoréMauvais format (--extra-vars="key=val" sans espace)Format correct : --extra-vars "key=val key2=val2" ou --extra-vars '{"key":"val"}'
vars_files: introuvableChemin relatif au playbook, pas au cwdTester avec ansible-playbook --syntax-check ou utiliser playbook_dir
Variable définie dans group_vars/ non vueLe group_vars/ doit être à côté de l’inventaire OU du playbookVérifier la doc Ansible sur les emplacements valides
Booléen non reconnuyes/no au lieu de true/falseMigrer vers la forme stricte YAML 1.2
Variable d’un rôle écrase celle du playroles/<role>/vars/main.yml est niveau 18 (haut)Utiliser defaults/main.yml (niveau 2) pour les overrides naturels
  • 5 emplacements principaux pour déclarer une variable : vars:, vars_files:, --extra-vars, group_vars/, host_vars/.
  • --extra-vars est le niveau 22 — le plus prioritaire, écrase tout.
  • group_vars/ et host_vars/ sont automatiquement chargés depuis l’inventaire ou le playbook.
  • Les types simples YAML 1.2 sont auto-détectés ; toujours quoter les valeurs ambiguës.
  • vars/ d’un rôle (niveau 18) écrase les vars: du play — préférer defaults/main.yml (niveau 2).

Cette page a un lab d’accompagnement : labs/ecrire-code/variables-base/ dans stephrobert/ansible-training. Il contient un README.md guidé, un Makefile (make verify lance les tests), et un challenge final auto-évalué : démontrer la précédence : —extra-vars > vars: du play > vars_files: dans un fichier marqueur.

Une fois le lab provisionné :

Fenêtre de terminal
cd ~/Projets/ansible-training/labs/ecrire-code/variables-base/
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