Maitriser les Boucles Ansible
Mise à jour :
Les boucles dans Ansible permettent d’automatiser l’exécution répétée d’une
tâche, avec des valeurs différentes à chaque itération. Que ce soit pour
installer plusieurs paquets, créer des utilisateurs ou configurer plusieurs
services, les boucles rendent vos playbooks Ansible plus lisibles, maintenables
et efficaces. Ce guide vous montre comment les utiliser, du simple loop
à des
constructions plus avancées comme les boucles imbriquées, les dictionnaires, et
les contrôles avec loop_control
.
Boucles de base : loop
La boucle loop
est la syntaxe moderne recommandée par Ansible pour répéter
une tâche sur une liste d’éléments. Elle remplace progressivement les anciennes
directives comme with_items
. Cependant, il existe des cas spécifiques où
l’usage de loop
est déconseillé, notamment avec certains modules acceptant
déjà des listes.
Traitement de liste simple
Voici un exemple typique pour créer plusieurs utilisateurs :
- name: Créer des utilisateurs ansible.builtin.user: name: "{{ item }}" state: present loop: - alice - bob - carol
Chaque itération passe une valeur à la variable spéciale item
. Le module
user
est alors exécuté pour chaque utilisateur.
loop
vs with_items
L’ancienne syntaxe with_items
reste fonctionnelle mais est moins lisible et
moins flexible :
- name: Créer des utilisateurs (ancienne méthode) ansible.builtin.user: name: "{{ item }}" state: present with_items: - alice - bob - carol
Préférez loop
pour les playbooks récents. Elle est plus cohérente avec les
autres boucles (loop_control
, until
, etc.).
Utiliser des listes complexes
Vous pouvez aussi itérer sur des listes de dictionnaires pour passer plusieurs arguments :
- name: Créer plusieurs groupes avec GID ansible.builtin.group: name: "{{ item.name }}" gid: "{{ item.gid }}" loop: - { name: 'dev', gid: 2001 } - { name: 'ops', gid: 2002 }
Ce format est utile pour passer plusieurs variables à chaque itération de la boucle.
Recommandations d’utilisation
Certains modules comme apt
, yum
ou package
acceptent une liste directement
dans leur paramètre. Inutile (et incorrect) d’utiliser loop
dans ces cas :
# ❌ Mauvais usage avec loop- name: Installer des paquets ansible.builtin.apt: name: "{{ item }}" state: present loop: - htop - curl
# ✅ Bon usage avec une liste directe- name: Installer plusieurs paquets ansible.builtin.apt: name: - htop - curl state: present
Utiliser loop
ici entraîne une exécution répétée du module, ce qui peut
ralentir les déploiements ou causer des effets indésirables.
Boucles sur dictionnaires et boucles imbriquées
Ansible permet également d’itérer sur des structures plus complexes, comme des dictionnaires ou des listes de listes. Cela permet de manipuler des données hiérarchisées ou de coupler plusieurs paramètres dans une même boucle.
Boucler sur un dictionnaire
Les dictionnaires (ou hashmaps) doivent être transformés en une liste de
paires clé-valeur pour pouvoir être parcourus avec loop
. Cela se fait grâce au
filtre dict2items
.
vars: utilisateurs: alice: "/home/alice" bob: "/home/bob"
tasks: - name: Créer les répertoires des utilisateurs ansible.builtin.file: path: "{{ item.value }}" state: directory owner: "{{ item.key }}" loop: "{{ utilisateurs | dict2items }}"
Ici, item.key
contient le nom de l’utilisateur et item.value
son répertoire.
Cette méthode est idéale pour mapper une clé à une propriété spécifique dans
une tâche.
Boucles imbriquées (nested loops)
Lorsque vous devez combiner deux listes, par exemple, affecter plusieurs rôles à chaque serveur, vous pouvez utiliser des boucles imbriquées.
vars: serveurs: - web1 - db1 roles: - nginx - firewalld
tasks: - name: Affecter chaque rôle à chaque serveur ansible.builtin.debug: msg: "Serveur {{ item[0] }} reçoit le rôle {{ item[1] }}" loop: "{{ serveurs | product(roles) | list }}"
Cette syntaxe utilise le filtre product
de Jinja2 pour effectuer un produit
cartésien des deux listes. Chaque item
devient une liste de deux éléments
([serveur, rôle]
).
Boucle imbriquée avec sous-liste
Il est également possible d’imbriquer une boucle dans une autre à l’aide de la
directive include_tasks
et d’une variable passée à la tâche incluse :
tasks: - name: Boucle principale include_tasks: sous_tache.yml loop: - app1 - app2 loop_control: loop_var: app_name
Fichier sous_tache.yml
:
- name: Tâche pour {{ app_name }} ansible.builtin.debug: msg: "Déploiement de {{ app_name }}"
Cette méthode est utile pour structurer proprement vos boucles complexes dans de grands playbooks.
Boucles conditionnelles et loop_control
Les boucles dans Ansible peuvent être combinées avec des conditions d’exécution et des options de contrôle d’affichage pour offrir un comportement plus fin et plus lisible. C’est particulièrement utile quand tous les éléments ne doivent pas être traités ou que vous voulez mieux suivre l’exécution de vos boucles.
Appliquer une condition dans une boucle
La directive when
permet de filtrer les éléments pendant la boucle. Elle
s’exécute à chaque itération et peut utiliser item
pour tester une valeur.
- name: Ajouter des utilisateurs sauf 'admin' ansible.builtin.user: name: "{{ item }}" state: present loop: - alice - bob - admin when: item != 'admin'
Dans cet exemple, le module user
sera exécuté uniquement pour alice
et
bob
.
Vous pouvez aussi filtrer selon une propriété spécifique dans une liste de dictionnaires :
- name: Créer les comptes actifs uniquement ansible.builtin.user: name: "{{ item.name }}" state: present loop: - { name: 'alice', actif: true } - { name: 'bob', actif: false } when: item.actif
Personnaliser l’affichage avec loop_control
La directive loop_control
vous donne un contrôle plus précis sur les variables
internes et l’affichage lors de l’exécution :
- name: Affichage avec étiquette personnalisée ansible.builtin.debug: msg: "Installation de {{ item.pkg }}" loop: - { pkg: 'htop', id: 1 } - { pkg: 'curl', id: 2 } loop_control: label: "{{ item.pkg }}"
Ici, la sortie affichera Installation de htop
plutôt que tout le dictionnaire
JSON.
Vous pouvez également suivre l’indice de boucle avec index_var
:
- name: Boucle avec index ansible.builtin.debug: msg: "Itération {{ index }} : {{ item }}" loop: - alpha - beta loop_control: index_var: index
Cela permet d’identifier rapidement à quelle étape du traitement on se trouve, ce qui est très utile pour le debug.
Combiner loop
, when
et loop_control
Les trois peuvent être utilisés ensemble pour des boucles puissantes et bien lisibles :
- name: Redémarrer les services actifs uniquement ansible.builtin.service: name: "{{ item.name }}" state: restarted loop: - { name: 'nginx', actif: true } - { name: 'mysql', actif: false } when: item.actif loop_control: label: "{{ item.name }}"
Dans cet exemple, seuls les services actifs seront redémarrés, et le nom du service sera affiché dans les logs.
Boucles avec until
et retry
Ansible offre un mécanisme de répétition conditionnelle avec until
,
permettant de réessayer une tâche jusqu’à ce qu’une condition soit remplie.
Contrairement à loop
, qui itère sur une liste, until
répète la même
tâche jusqu’à obtenir un résultat attendu. C’est très utile pour les
vérifications de services ou les appels à des API instables.
Syntaxe de base avec until
Voici un exemple de tâche qui vérifie qu’un fichier existe, avec répétition toutes les 5 secondes pendant 30 secondes maximum :
- name: Attendre qu’un fichier soit créé ansible.builtin.stat: path: /tmp/mon_fichier register: fichier until: fichier.stat.exists retries: 6 delay: 5
Cette tâche :
- S’exécute jusqu’à ce que
fichier.stat.exists
soit vrai, - Fait 6 tentatives avec 5 secondes d’intervalle,
- Soit un total de 30 secondes maximum.
Exemple avec un service en attente
Le cas typique : attendre que MySQL réponde sur le port 3306 avant de lancer les migrations.
- name: Attendre que MySQL réponde ansible.builtin.wait_for: host: 127.0.0.1 port: 3306 state: started register: result until: result is succeeded retries: 10 delay: 3
Ce mécanisme permet d’éviter les erreurs liées à des dépendances non encore disponibles. Cela rend vos playbooks plus robustes et moins sensibles aux délais de démarrage.
until
combiné avec des boucles
Il est tout à fait possible de combiner loop
et until
, même si la logique
devient plus complexe. Par exemple, pour vérifier la présence de plusieurs
fichiers :
- name: Vérifier plusieurs fichiers ansible.builtin.stat: path: "{{ item }}" register: res until: res.stat.exists retries: 5 delay: 2 loop: - /tmp/fichier1 - /tmp/fichier2
Chaque fichier est vérifié individuellement, et chaque itération bénéficie
d’une répétition autonome avec until
.
Bonnes pratiques avec until
- N’abusez pas des répétitions : limitez le nombre de retries pour éviter des déploiements trop longs.
- Utilisez toujours
register
pour stocker la sortie. - Combinez
until
avecdebug
pour comprendre les blocages.
Exercices pratiques : Maîtriser les boucles Ansible
Vous avez désormais toutes les clés pour écrire des boucles efficaces avec
Ansible : de la simple itération à la combinaison loop + when
, sans oublier
les structures complexes comme les dictionnaires et les boucles
imbriquées. Passons maintenant à la pratique, avec une série de travaux
concrets pour créer des tâches dynamiques, conditionnelles et lisibles.
👉 Travaux pratiques : TP 10 : Boucles Ansible ↗
Ces exercices couvrent notamment
- L’écriture de playbooks utilisant
loop
pour créer des utilisateurs, des groupes ou des fichiers personnalisés. - La transformation d’un dictionnaire avec
dict2items
pour générer des ressources conditionnelles. - L’utilisation de
loop_control
pour nommer les boucles, suivre les indices, et faciliter le debug. - L’intégration de
until
dans une tâche qui attend un état cible (ex. : fichier présent, service disponible).
Pourquoi pratiquer ?
- Savoir distinguer quand utiliser une liste directe (par exemple pour
apt
) ou une boucle explicite. - Optimiser vos playbooks Ansible en réduisant les tâches redondantes et en améliorant leur lisibilité.
- Créer des structures dynamiques capables de s’adapter à des données complexes (nested loops, conditions).
- Déboguer une boucle efficacement en exploitant les variables internes (
item
,index_var
,label
, etc.).
Clonez le dépôt ou suivez les consignes directement dans les fichiers. Grâce à ces exercices ciblés, vous saurez écrire des boucles fiables, maintenables et adaptées à chaque contexte d’automatisation.
Contrôle de connaissances
Pourquoi ce contrôle ?
Cet contrôle va vous permettre de valider vos connaissances sur le sujet abordé dans le guide. Il comporte des QCM, des questions vrai/faux et des réponses ouvertes à un mot.
🕒 Le chronomètre commence dès que vous cliquez sur Démarrer le test. Vous devrez terminer l’examen avant la fin du temps imparti.
🎯 Pour réussir, vous devez obtenir au moins 80% de bonnes réponses.
💡 Je ne fournis pas directement les réponses aux questions. Cependant, si certaines sont complexes, des pistes d’explication pourront être proposées dans le guide ou après l’examen.
Bonne chance ! 🚀
Conclusion
Vous avez maintenant une compréhension solide des boucles dans Ansible, de
l’utilisation de loop
pour itérer sur des listes simples, à la manipulation de
dictionnaires et de boucles imbriquées. Vous savez comment appliquer des
conditions avec when
, personnaliser l’affichage avec loop_control
, et gérer
les répétitions conditionnelles avec until
. Nous verrons dans un prochain
chapitre d’autres types de boucles.