Tu sais installer Ansible et créer un inventaire. Maintenant, on passe à l’arme principale : les playbooks. C’est ici que tu passes de « lancer des commandes une par une » à « décrire l’état souhaité de ton infra en un fichier ». Ce chapitre te donne les modules essentiels, la structure d’un playbook, et un déploiement Nginx complet — comme tu le ferais en entreprise.
Pourquoi les playbooks changent tout
Un script Bash, tu le lances deux fois, tu as deux fois le résultat (ou pire, des erreurs). Un playbook Ansible, tu le lances dix fois : si l’état est déjà conforme, il ne touche à rien. C’est le principe d’idempotence, et c’est ce qui rend l’Infrastructure as Code fiable.
Les playbooks apportent trois choses que les scripts n’ont pas :
- Lisibilité — du YAML structuré, pas du Bash spaghetti
- Reproductibilité — même playbook, même résultat, que ce soit sur 1 ou 200 serveurs
- Traçabilité — versionné dans Git, chaque changement est auditable
🔥 Cas réel — Une équipe ops gérait 40 serveurs Nginx avec des scripts Bash copiés-collés. Quand un stagiaire a modifié le mauvais script, 12 serveurs se sont retrouvés avec une config cassée. Avec un playbook unique versionné dans Git, le rollback aurait pris 30 secondes au lieu de 3 heures.
🧠 À retenir — Un playbook décrit un état désiré, pas une séquence d’actions. Ansible se charge de combler l’écart entre l’état actuel et l’état cible.
Comprendre l’anatomie d’un playbook
Un playbook, c’est un fichier YAML composé d’un ou plusieurs plays. Chaque play cible un groupe de machines et contient des tasks (tâches). Chaque tâche appelle un module avec des paramètres.
Voici la structure minimale pour comprendre chaque brique :
---
- name: Mon premier play # Nom du play (affiché à l'exécution)
hosts: webservers # Groupe ciblé dans l'inventaire
become: yes # Escalade de privilèges (sudo)
vars:
site_name: monsite # Variables du play
tasks:
- name: Installer Nginx # Nom de la tâche
ansible.builtin.apt: # Module appelé (FQCN)
name: nginx
state: present # État désiré
handlers:
- name: Recharger Nginx # Handler = tâche conditionnelle
ansible.builtin.service:
name: nginx
state: reloaded
Les handlers sont des tâches spéciales : elles ne s’exécutent que si une tâche les notifie via notify. Typiquement, tu notifies un handler « Recharger Nginx » quand tu modifies un fichier de config. Si le fichier n’a pas changé, le handler ne se déclenche pas.
💡 Tip DevOps — Utilise toujours les FQCN (Fully Qualified Collection Names) comme ansible.builtin.apt plutôt que juste apt. Ça évite les conflits entre collections et c’est la convention officielle depuis Ansible 2.10.
Les commandes indispensables
Avant de lancer un playbook en production, tu as trois niveaux de vérification. Prends l’habitude de toujours passer par les deux premiers.
La commande --syntax-check valide la syntaxe YAML sans rien exécuter. Le mode --check --diff simule l’exécution et affiche ce qui changerait. Et ensuite seulement, tu appliques :
# 1. Vérifier la syntaxe YAML
ansible-playbook playbook.yml -i inventory.ini --syntax-check
# 2. Dry-run : simuler sans appliquer
ansible-playbook playbook.yml -i inventory.ini --check --diff
# 3. Exécuter pour de vrai
ansible-playbook playbook.yml -i inventory.ini
Pour les tests rapides sans playbook, les commandes ad-hoc sont ton couteau suisse. Elles utilisent -m pour spécifier le module :
# Tester la connectivité SSH
ansible all -i inventory.ini -m ping
# Vérifier l'uptime
ansible all -i inventory.ini -m command -a "uptime"
# Installer un paquet en one-shot
ansible webservers -i inventory.ini -m apt -a "name=curl state=present" --become
⚠️ Attention — Le mode --check ne garantit pas que l’exécution réelle fonctionnera. Certains modules ne supportent pas le check mode, et des dépendances entre tâches peuvent fausser la simulation. Teste toujours sur un environnement de staging d’abord.
Cas concret : déployer Nginx en production
Voici un scénario réaliste. Tu dois déployer Nginx sur un groupe de serveurs web avec une page d’accueil et une config personnalisée. Ton arborescence de projet ressemble à ça :
projet-nginx/
├── inventory.ini
├── deploy-nginx.yml
├── files/
│ └── index.html
└── templates/
└── vhost.conf.j2
Le template Jinja2 permet de générer une config différente par serveur grâce aux variables. Contrairement à copy qui copie un fichier tel quel, template interprète les expressions {{ }} avant de déposer le fichier :
server {
listen 80 default_server;
root /var/www/{{ site_name }};
server_name {{ ansible_hostname }};
location / {
try_files $uri $uri/ =404;
}
}
Et voici le playbook complet qui orchestre l’installation, la configuration et le démarrage du service :
---
- name: Déployer Nginx sur les serveurs web
hosts: webservers
become: yes
vars:
site_name: monsite
tasks:
- name: Installer Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: yes
cache_valid_time: 3600
- name: Créer le répertoire du site
ansible.builtin.file:
path: "/var/www/{{ site_name }}"
state: directory
owner: www-data
group: www-data
- name: Déployer la page d'accueil
ansible.builtin.copy:
src: files/index.html
dest: "/var/www/{{ site_name }}/index.html"
owner: www-data
mode: "0644"
- name: Configurer le vhost Nginx
ansible.builtin.template:
src: templates/vhost.conf.j2
dest: /etc/nginx/sites-available/default
notify: Recharger Nginx
- name: S'assurer que Nginx est démarré
ansible.builtin.service:
name: nginx
state: started
enabled: yes
handlers:
- name: Recharger Nginx
ansible.builtin.service:
name: nginx
state: reloaded
🔥 Cas réel — Ce playbook, tu le retrouves sous une forme ou une autre dans 90% des entreprises qui utilisent Ansible. La première automatisation, c’est presque toujours un serveur web. Une fois que tu maîtrises ce pattern (install → config → service → handler), tu peux l’adapter à n’importe quel service : PostgreSQL, Redis, HAProxy…
Quand tu relances ce playbook sur des serveurs déjà configurés, la sortie affiche ok partout au lieu de changed. C’est l’idempotence : Ansible vérifie l’état actuel avant d’agir.
Les pièges qui font perdre des heures
L’indentation YAML. C’est la source d’erreur n°1. Un espace en trop ou en moins et tout casse. Utilise un éditeur avec un linter YAML activé.
Oublier become: yes. Sans escalade de privilèges, les tâches qui nécessitent root échouent avec un message parfois cryptique. Si tu installes des paquets ou modifies des fichiers système, tu as besoin de become.
Confondre copy et template. Si ton fichier contient des {{ variables }}, utilise template. Avec copy, les expressions Jinja2 sont copiées telles quelles — pas interprétées.
Les handlers qui ne se déclenchent pas. Un handler ne s’exécute que si la tâche qui le notifie a le statut changed. Si le fichier n’a pas changé, pas de notification, pas de reload. C’est voulu, mais ça surprend au début.
Ne pas nommer ses tâches. Un playbook sans name: fonctionne, mais la sortie devient illisible. Quand une tâche échoue sur 50 serveurs, tu veux voir « Configurer le vhost Nginx » plutôt que « TASK [ansible.builtin.template] ».
⚠️ Attention — Ne fais jamais state: latest en production sans tester. Tu risques de mettre à jour un paquet vers une version incompatible. Préfère state: present et gère les upgrades de manière contrôlée.
Exercice et points clés
Exercice — Playbook multi-services
Écris un playbook qui fait les 4 étapes suivantes sur un serveur Ubuntu :
- Installe
nginx,curlethtopen une seule tâche (le moduleaptaccepte une liste dansname) - Déploie un fichier
index.htmlpersonnalisé viatemplate(avec une variablemessage) - Configure un handler qui recharge Nginx uniquement si la config change
- Ajoute une tâche de vérification avec le module
uripour confirmer que le site répond en HTTP 200
Pour la vérification, voici le module à utiliser :
- name: Vérifier que le site répond
ansible.builtin.uri:
url: "http://localhost"
status_code: 200
💡 Tip DevOps — Versionne ton playbook dans Git dès la première ligne. Pas « quand il sera propre », pas « quand il marchera ». Maintenant. Un git init + git commit prend 10 secondes et peut te sauver des heures.
🧠 À retenir — Les 5 points essentiels de ce chapitre :
- Un playbook décrit un état désiré, pas des actions séquentielles
- L’idempotence garantit que relancer = vérifier, pas casser
- Toujours
--check --diffavant d’appliquer en production - Les handlers optimisent les redémarrages (seulement si changement)
templatepour les fichiers dynamiques,copypour les fichiers statiques
Dans le prochain chapitre, on plonge dans les variables, facts et templates Jinja2 pour rendre tes playbooks véritablement dynamiques.
Cet article fait partie de la série Apprendre Ansible sur devopslab.ch — des cours DevOps gratuits, en français, pensés pour la pratique.
🎓 Examen de fin de chapitre
Teste tes connaissances avec cet examen de 10 questions. Il faut 70% de bonnes réponses pour obtenir le badge du chapitre.
📤 Soumettre ton travail
Tu as terminé le chapitre ? Soumets ton code ou ta configuration pour obtenir un review automatique par IA.
🖥️ Pratique sur ton propre serveur
Pour suivre Ansible en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Ansible
2 / 8Sur cette page
Articles liés
Pourquoi Ansible ? L'automatisation simplifiée
Découvre Ansible : pourquoi l'automatisation est essentielle, architecture agentless, installation, inventaire et premières commandes ad-hoc.
Déploiement avancé et orchestration
Stratégies de déploiement rolling et canary, intégration CI/CD avec GitHub Actions, et AWX / Ansible Automation Platform.
Variables et priorités
Maîtrise la hiérarchie des variables Ansible, host_vars et group_vars, et sécurise tes secrets avec Ansible Vault.