Aller au contenu principal
AnsibleInfrastructure as CodeFormation

Playbooks et modules essentiels

30 min de lecture Ansible — Chapitre 2

Les modules essentiels d'Ansible et ton premier playbook complet pour déployer Nginx. De la théorie à la pratique.

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 :

  1. Installe nginx, curl et htop en une seule tâche (le module apt accepte une liste dans name)
  2. Déploie un fichier index.html personnalisé via template (avec une variable message)
  3. Configure un handler qui recharge Nginx uniquement si la config change
  4. Ajoute une tâche de vérification avec le module uri pour 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 --diff avant d’appliquer en production
  • Les handlers optimisent les redémarrages (seulement si changement)
  • template pour les fichiers dynamiques, copy pour 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.

Obtenir 200$

Articles liés