
Cette page est une cheat-sheet de survie. Elle présente les 15 modules Ansible que vous allez croiser dès le premier playbook — bien avant d’avoir lu les guides détaillés qui leur sont dédiés. L’objectif est simple : vous donner le squelette minimal de chaque module pour ne pas être perdu quand un lab ou un guide les utilise en filigrane.
Chaque entrée suit le même format : quand l’utiliser, squelette le plus court, exemple concret, lien vers le guide complet. Quelques minutes de lecture suffisent à parcourir l’ensemble — gardez cette page ouverte pendant vos premiers labs.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Les 15 modules que vous croiserez dans 90% des playbooks débutants.
- Le squelette minimal de chaque module (5-10 lignes).
- Comment distinguer des modules proches (
copyvstemplate,commandvsshell). - Vers quel lab dédié aller pour approfondir chaque module.
ansible.builtin.debug
Section intitulée « ansible.builtin.debug »Quand l’utiliser : afficher la valeur d’une variable ou un message dans le PLAY RECAP. C’est l’équivalent du print() Python — votre meilleur allié pour comprendre ce qu’Ansible voit.
- name: Afficher une variable ansible.builtin.debug: var: ansible_distribution # → "ansible_distribution": "AlmaLinux"
- name: Afficher un message custom ansible.builtin.debug: msg: "OS detecte : {{ ansible_distribution }} {{ ansible_distribution_version }}"Pas de lab dédié — vous l’utiliserez partout dès les premiers playbooks. Plus de détails dans la doc Ansible officielle (builtin.debug).
ansible.builtin.copy
Section intitulée « ansible.builtin.copy »Quand l’utiliser : transférer un fichier du control node vers le managed node, ou écrire un contenu inline.
# Transfert d un fichier local- ansible.builtin.copy: src: files/banner.txt dest: /etc/issue.net owner: root group: root mode: "0644"
# Contenu inline- ansible.builtin.copy: content: "Provisionne par Ansible\n" dest: /etc/ansible-managed mode: "0644"Pièges classiques : oublier le \n final dans content:, oublier les guillemets sur mode: "0644" (sinon YAML décimal). Voir Lab 31 — Module copy.
ansible.builtin.file
Section intitulée « ansible.builtin.file »Quand l’utiliser : gérer l’état d’un fichier ou répertoire sans transférer de contenu — créer un dossier, supprimer un fichier, créer un symlink, ajuster les permissions.
# Creer un repertoire- ansible.builtin.file: path: /var/log/myapp state: directory owner: nobody mode: "0750"
# Supprimer un fichier (ou un dossier — recursif)- ansible.builtin.file: path: /etc/old-config.conf state: absent
# Symlink- ansible.builtin.file: src: /opt/myapp/releases/v1.0.0 dest: /opt/myapp/current state: link force: true6 valeurs de state: : file, directory, absent, link, hard, touch. Voir Lab 32 — Module file.
ansible.builtin.lineinfile
Section intitulée « ansible.builtin.lineinfile »Quand l’utiliser : modifier ou ajouter une seule ligne dans un fichier existant — sans toucher au reste. Idéal pour les configs partagées (/etc/sysctl.conf, /etc/hosts).
- ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin' line: 'PermitRootLogin no' backup: true validate: 'sshd -t -f %s' notify: Reload sshdToujours mettre regexp: quand vous modifiez une option existante — sans regexp, Ansible empile une nouvelle ligne à chaque run. Voir Lab 30 — lineinfile vs template.
ansible.builtin.template
Section intitulée « ansible.builtin.template »Quand l’utiliser : générer un fichier complet depuis un template Jinja2 avec interpolation de variables. Successeur de copy: quand vous avez besoin de logique.
- ansible.builtin.template: src: templates/myapp.conf.j2 dest: /etc/myapp.conf owner: root group: root mode: "0644" backup: true validate: 'myapp --check-config %s' lstrip_blocks: true trim_blocks: trueLe template .j2 vit dans templates/ du playbook. Toujours activer lstrip_blocks: true + trim_blocks: true pour le whitespace control. Voir Lab 29 — Module template.
ansible.builtin.dnf (RHEL) / package (multi-distro)
Section intitulée « ansible.builtin.dnf (RHEL) / package (multi-distro) »Quand l’utiliser : installer ou supprimer des paquets. Sur RHEL/AlmaLinux/Rocky, préférer dnf: (options spécifiques). Sur multi-distro, package: suffit.
# RHEL : dnf- ansible.builtin.dnf: name: - vim-enhanced - htop - tree state: present
# Multi-distro : package- ansible.builtin.package: name: nginx state: presentstate: accepte : present (défaut), latest (à éviter en prod — upgrade systématique), absent. Toujours préférer la liste dans name: plutôt qu’une boucle (3-5× plus rapide). Voir Lab 36 — package et Lab 37 — dnf options.
ansible.builtin.systemd_service
Section intitulée « ansible.builtin.systemd_service »Quand l’utiliser : gérer un service systemd (RHEL 7+, Ubuntu 16.04+) — démarrer, arrêter, recharger, activer au boot.
- ansible.builtin.systemd_service: name: chronyd state: started # started | stopped | restarted | reloaded enabled: true # Au boot
# Apres un nouveau unit file dans /etc/systemd/system/- ansible.builtin.systemd_service: name: myapp state: started enabled: true daemon_reload: truestate: (immédiat) et enabled: (boot) sont indépendants. Préférer reloaded à restarted quand le service le supporte. Voir Lab 38 — systemd_service.
ansible.builtin.user
Section intitulée « ansible.builtin.user »Quand l’utiliser : créer, modifier ou supprimer un utilisateur Linux.
- ansible.builtin.user: name: alice shell: /bin/bash groups: [wheel, docker] append: true state: present password: "{{ 'plain_password' | password_hash('sha512') }}"Bonnes pratiques : append: true pour ajouter aux groupes sans écraser les existants ; password hashé côté Ansible avec password_hash('sha512') — voir Lab 27 — Filtres Jinja2 avancés.
ansible.builtin.stat
Section intitulée « ansible.builtin.stat »Quand l’utiliser : récupérer des informations sur un fichier ou dossier (existence, taille, mode, owner, checksum). C’est le module n°1 pour la logique conditionnelle.
- ansible.builtin.stat: path: /etc/myapp.conf register: myapp_stat
- name: Action si le fichier existe et est non vide ansible.builtin.copy: content: "ok\n" dest: /tmp/marker.txt when: myapp_stat.stat.exists and myapp_stat.stat.size > 0Champs courants : .stat.exists, .stat.isfile, .stat.isdir, .stat.size, .stat.mode, .stat.checksum. Pas de lab dédié — utilisé en duo avec register: + when: (cf. Lab 16).
ansible.builtin.uri
Section intitulée « ansible.builtin.uri »Quand l’utiliser : faire un appel HTTP depuis le managed node (équivalent curl). Pratique pour les healthchecks, les appels API, les webhooks.
- ansible.builtin.uri: url: http://localhost:8080/health method: GET status_code: [200, 204] return_content: true register: health_check
- ansible.builtin.debug: msg: "Body : {{ health_check.json | default(health_check.content) }}"Champs utiles du register : .status, .content, .json (parsé automatiquement si Content-Type: application/json). Pas de lab dédié — couvert en filigrane dans plusieurs labs.
ansible.builtin.assert
Section intitulée « ansible.builtin.assert »Quand l’utiliser : valider une condition au début d’un play et échouer fail-fast si elle n’est pas satisfaite. Outil de programmation défensive.
- name: Valider les prerequis ansible.builtin.assert: that: - ansible_distribution == "AlmaLinux" - ansible_distribution_major_version | int >= 9 - app_config is defined - app_config.port is integer fail_msg: "Prerequis non remplis — voir les conditions ci-dessus" success_msg: "Tous les prerequis sont valides"Préférer assert: à un long when: quand la validation est explicitement le but de la tâche. Voir Lab 28 — Tests Jinja2.
ansible.builtin.set_fact
Section intitulée « ansible.builtin.set_fact »Quand l’utiliser : créer une variable au runtime dans un play, à partir d’une logique de calcul ou d’une capture précédente.
- name: Calculer un label de deploy ansible.builtin.set_fact: deploy_label: "{{ inventory_hostname }}-{{ ansible_date_time.epoch }}"
- name: Utiliser le label ansible.builtin.copy: content: "Label : {{ deploy_label }}\n" dest: /tmp/marker.txtNiveau 18 dans la précédence — bat vars: du play (niveau 14). Pour persister entre runs : ajouter cacheable: true (nécessite fact_caching configuré). Voir Lab 16 — register et set_fact.
ansible.builtin.pause
Section intitulée « ansible.builtin.pause »Quand l’utiliser : attendre un nombre de secondes, ou demander une confirmation interactive à l’opérateur. Utile pour les rolling updates et les opérations critiques.
- name: Attendre 5s pour laisser le service redemarrer ansible.builtin.pause: seconds: 5
- name: Confirmer manuellement avant la migration ansible.builtin.pause: prompt: "Appuyez sur ENTREE pour continuer la migration BDD"Cas d’usage typique : entre un restart et un healthcheck, pour laisser le service finir son init. Pas de lab dédié — utilisé dans les labs 09 (parallélisme) et 10 (async).
ansible.posix.firewalld
Section intitulée « ansible.posix.firewalld »Quand l’utiliser : ouvrir/fermer un port dans firewalld (RHEL/AlmaLinux/Rocky). Module fourni par la collection ansible.posix (pas builtin).
- name: Ouvrir le port 80 (HTTP) ansible.posix.firewalld: service: http state: enabled permanent: true immediate: true
# Port custom- name: Ouvrir le port 8443 ansible.posix.firewalld: port: 8443/tcp state: enabled permanent: true immediate: trueToujours permanent: true ET immediate: true — sinon la règle est appliquée maintenant mais disparaît au reboot, ou inversement. Phase 4.5 du parcours (à venir) couvrira en détail.
Pourquoi les modules dédiés sont idempotents
Section intitulée « Pourquoi les modules dédiés sont idempotents »Avant de découvrir les trois modules d’exécution brute (raw, command, shell), il faut comprendre ce qui rend les autres idempotents — parce que c’est exactement ce qui manque à ces trois-là.
Quand vous écrivez ansible.builtin.dnf: name=nginx state=present, Ansible n’exécute pas bêtement dnf install nginx. Il transfère sur la cible un script Python (le module dnf) qui :
- Lit l’état actuel :
rpm -q nginxpour vérifier si le paquet est déjà installé. - Compare à l’état désiré demandé (
state: present). - N’agit que si nécessaire :
dnf installlancé seulement si le paquet manque, sinon retourchanged=falseimmédiat.
Tous les modules dédiés suivent ce schéma lecture → comparaison → action conditionnelle. Le module file lit stat avant de modifier le mode. Le module copy calcule un checksum SHA-256 et compare au fichier distant avant de transférer. Le module lineinfile lit le fichier ligne par ligne et applique le regexp: avant d’écrire. C’est le code Python du module qui implémente l’idempotence — Ansible lui-même n’en sait rien, il fait juste circuler des dictionnaires JSON.
Cette propriété a un coût : écrire un module idempotent est plus complexe que d’écrire un script shell. C’est pour ça qu’il en existe plus de 3 000 dans l’écosystème Ansible — chacun encapsule la logique « état actuel vs état désiré » d’un domaine précis (paquets, services, firewall, utilisateurs…). Quand vous utilisez le bon module, vous héritez gratuitement de tout ce travail.
Modules d’exécution brute — uniquement en dernier recours
Section intitulée « Modules d’exécution brute — uniquement en dernier recours »raw, command, shell font l’inverse : ils exécutent une commande arbitraire sur la cible. Ansible n’a aucun moyen générique de savoir ce que cette commande va faire ni si elle a déjà produit l’effet attendu — il l’exécute donc à chaque run, ce qui marque la tâche changed=true à chaque exécution et casse l’idempotence de votre playbook.
Règle absolue : avant d’écrire command: ou shell:, cherchez le module dédié avec ansible-doc -l | grep <thème>. Si vous écrivez shell: dnf install -y nginx, vous écrivez du Bash en YAML — c’est un échec de conception, pas une simplification. Ces modules existent pour les 3 cas légitimes suivants :
- Aucun module dédié n’existe pour la tâche (cas rare en 2026 — vérifiez deux fois avant d’y croire).
- Bootstrap d’un host sans Python : le seul cas où
rawest obligatoire (Ansible ne peut pas exécuter de module Python tant que Python 3 n’est pas installé). - Lecture-seule pour récupérer une valeur dans une variable (
register:) — toujours avecchanged_when: false.
ansible.builtin.raw
Section intitulée « ansible.builtin.raw »Quand l’utiliser : exécuter une commande sans Python côté cible. Le seul cas légitime : bootstrapper Python 3 sur une image minimale (RHEL UBI, Alpine, équipement réseau Cisco/Junos).
- name: Installer Python 3 sur un host sans Python ansible.builtin.raw: which python3 || dnf install -y python3 register: py_install changed_when: "'Installed' in py_install.stdout"gather_facts: false est obligatoire dans le play — sinon Ansible essaie d’exécuter le module setup qui demande Python. Une fois Python installé via raw, basculez sur les modules normaux dans les plays suivants.
ansible.builtin.command
Section intitulée « ansible.builtin.command »Quand l’utiliser : exécuter une commande sans shell (pas de pipe |, pas de redirection >, pas de glob *). C’est la forme préférée entre les deux quand vous avez besoin d’exécuter un binaire — Ansible passe directement les arguments sans interprétation shell, ce qui ferme la porte aux injections.
- name: Lire la version d openssl (lecture-seule) ansible.builtin.command: openssl version register: ssl_version changed_when: false
- name: Lancer un script qui crée un fichier marqueur (idempotent grâce à creates:) ansible.builtin.command: /usr/local/bin/init-db.sh args: creates: /var/lib/myapp/.initializedGarde-fous d’idempotence :
changed_when: falsesur toute commande lecture-seule (sinonchanged=1à chaque run).creates: <chemin>: la tâche est skippée si le fichier existe — utile pour les scripts d’init.removes: <chemin>: la tâche est skippée si le fichier n’existe pas — utile pour les scripts de nettoyage.
Voir ecrire-code/failed-when-changed-when pour le détail.
ansible.builtin.shell
Section intitulée « ansible.builtin.shell »Quand l’utiliser : comme command: mais avec shell (pipe, redirection, expansion de variables). À utiliser seulement si vous avez vraiment besoin d’une fonctionnalité shell — sinon préférer command: pour la sécurité.
- name: Compter les lignes contenant "Error" ansible.builtin.shell: | grep -c "Error" /var/log/myapp.log || true register: error_count changed_when: falseRègle de choix : besoin de |, >, *, && ? → shell:. Sinon → command:. Et dans tous les cas : avez-vous vraiment vérifié qu’aucun module dédié n’existe ?
Comment savoir quel module utiliser ?
Section intitulée « Comment savoir quel module utiliser ? »Quand vous savez ce que vous voulez faire mais pas quel module, ces 4 questions guident le choix :
- “Modifier un fichier” →
copy:(statique),template:(avec variables),lineinfile:(1 ligne),blockinfile:(3-10 lignes). - “Gérer un fichier” (sans toucher au contenu) →
file:(mode, owner, état). - “Gérer un paquet/service” →
dnf:(RHEL) oupackage:(multi-distro),systemd_service:(services). - “Exécuter une commande arbitraire” → vérifier d’abord avec
ansible-doc -l | grep <thème>qu’aucun module dédié n’existe. Si vraiment rien :command:(sans shell, préféré),shell:(avec pipe/redirection),raw:(sans Python). Toujours avec un garde-fou (creates:,removes:ouchanged_when:).
Pour tout le reste, la doc officielle est l’outil de recherche : Ansible builtin modules.
Pièges récurrents communs aux modules
Section intitulée « Pièges récurrents communs aux modules »Trois pièges qui touchent plusieurs modules à la fois :
mode: 0644non quoté → YAML décimal au lieu d’octal. Toujoursmode: "0644"(avec guillemets).{{ }}danswhen:,failed_when:,changed_when:→ warning Ansible 2.16+. Ces directives sont déjà des expressions Jinja2.register:+loop:→ la variable contient.results(liste), pas.stdoutdirectement. Voir Lab 16.
À retenir
Section intitulée « À retenir »- 15 modules suffisent pour 90% des playbooks débutants.
- Cette page est une référence rapide — gardez-la ouverte pendant vos premiers labs.
- Chaque module a un squelette minimal de 5-10 lignes — pas besoin de tout connaître au départ.
- Convention RHCE 2026 : préfixer toujours par le namespace (
ansible.builtin.copy, pascopy). - Les labs dédiés approfondissent chaque module avec exercices et challenges pytest.