Gérer plusieurs serveurs avec Ansible facilement
Gérer plusieurs serveurs peut vite devenir une expérience épuisante lorsqu’on commence à tout faire à la main. Au début, cela semble presque simple : un serveur web ici, un serveur de base de données là, un serveur de sauvegarde, un autre pour la surveillance, et puis encore un environnement de test, un préproduction, un production. On se dit souvent que quelques commandes SSH bien placées suffiront. Puis le nombre de machines augmente, les configurations se multiplient, les différences entre environnements deviennent plus difficiles à suivre, et l’on finit par passer plus de temps à corriger des écarts qu’à faire avancer le projet. C’est précisément dans ce genre de contexte qu’Ansible prend tout son sens.
Ansible n’est pas seulement un outil d’automatisation. C’est une manière plus sereine de penser l’administration système. Il aide à décrire l’état désiré de vos serveurs, puis à appliquer cet état de manière répétable, lisible et contrôlée. Avec lui, vous pouvez installer des paquets, créer des utilisateurs, déployer des fichiers de configuration, redémarrer des services, exécuter des tâches à distance, orchestrer des déploiements, et surtout le faire sur plusieurs serveurs en même temps, sans devoir réécrire la même logique encore et encore.
Ce qui rend Ansible particulièrement agréable, c’est son approche déclarative et son fonctionnement sans agent. Vous n’avez pas besoin d’installer un daemon spécifique sur chaque machine cible. Un accès SSH suffit dans la majorité des cas. Cela simplifie l’adoption, réduit la maintenance et évite une couche supplémentaire de complexité. Pour une petite équipe comme pour une organisation plus grande, ce détail change beaucoup de choses. On gagne du temps, on diminue les erreurs humaines et on rend l’infrastructure plus facile à comprendre.
Dans cet article, nous allons voir comment gérer plusieurs serveurs avec Ansible facilement, pas seulement en théorie, mais avec une vraie logique d’organisation. Nous allons parler des inventaires, des playbooks, des rôles, des variables, des templates, des handlers, des bonnes pratiques, de la sécurité, des erreurs fréquentes et des méthodes pour garder vos automatisations propres, maintenables et évolutives. L’objectif n’est pas juste de lancer une commande. L’objectif est d’apprendre à construire une base solide, celle qui vous permettra d’automatiser vos serveurs sans vous perdre dans votre propre configuration.
Pourquoi Ansible est devenu un réflexe pour l’administration moderne
Dans les environnements classiques, on administrait souvent les serveurs de manière artisanale. On se connectait à une machine, on changeait quelques fichiers, on redémarrait un service, puis on reproduisait l’opération sur une autre machine avec quelques variantes. Au début, cela fonctionne. Puis vient le moment où l’on ne sait plus exactement quelle version de configuration tourne sur quel serveur. Un serveur a été modifié vendredi soir, un autre après un incident, un troisième lors d’un test rapide. Les écarts s’installent, parfois discrètement, et les bugs deviennent difficiles à reproduire.
Ansible apporte une réponse élégante à ce problème : au lieu de faire confiance à la mémoire humaine, on écrit les opérations dans des fichiers versionnés. Ces fichiers deviennent la source de vérité. Ils peuvent être relus, testés, partagés, validés en revue de code et rejoués à l’identique. Cette reproductibilité est un soulagement. Elle réduit la charge mentale et améliore la collaboration entre les équipes.
Il y a aussi un autre avantage très concret : Ansible parle le langage du système. Les tâches ressemblent souvent à ce que ferait un administrateur humain, mais de façon structurée. Installer un paquet, copier un fichier, créer un service systemd, modifier une variable d’environnement, appliquer des permissions, redémarrer un démon, tout cela devient clair et lisible. Même quelqu’un qui découvre le projet peut comprendre assez vite ce que fait l’automatisation.
Un autre point fort, souvent sous-estimé, est la facilité avec laquelle Ansible s’adapte à plusieurs serveurs hétérogènes. Vous pouvez cibler un groupe de machines web, un groupe de bases de données, un groupe de monitoring, ou encore appliquer une même logique à des serveurs de régions différentes. L’inventaire et les variables vous permettent de gérer cette diversité sans écrire une usine à gaz.
Comprendre le modèle mental d’Ansible
Avant de parler d’exemples concrets, il faut bien comprendre comment Ansible pense.
Ansible fonctionne autour de quelques éléments essentiels :
l’inventaire, qui décrit les machines cibles ;
les playbooks, qui décrivent les tâches à exécuter ;
les modules, qui réalisent les actions concrètes ;
les rôles, qui organisent le code de manière modulaire ;
les variables, qui paramètrent le comportement ;
les templates, qui génèrent des fichiers dynamiques ;
les handlers, qui exécutent certaines actions seulement quand c’est nécessaire.
Cette structure peut sembler abstraite au départ, mais elle devient très naturelle dès que l’on commence à construire un vrai projet. Le secret est de ne pas tout mettre dans un seul fichier. Beaucoup de débutants créent un playbook géant avec des dizaines de tâches mélangées. Cela marche un moment, puis cela devient ingérable. La bonne approche consiste à découper la logique en blocs cohérents, à externaliser les variables, et à réutiliser ce qui peut l’être.
Le fonctionnement est aussi résolument idempotent. Cela signifie qu’exécuter le même playbook plusieurs fois ne devrait pas casser l’état du système ni répéter inutilement des changements déjà appliqués. Si une tâche a déjà fait son travail, Ansible le détecte et évite l’action superflue. Cette propriété est essentielle quand on gère plusieurs serveurs, parce qu’elle permet de rejouer des automatisations en toute confiance.
Installer Ansible sur la machine de contrôle
Ansible s’exécute depuis une machine de contrôle. C’est depuis cette machine que vous orchestrez vos serveurs distants. Elle peut être votre ordinateur local, une machine dédiée d’administration, ou un serveur CI/CD.
Sur une distribution Linux de type Debian ou Ubuntu, l’installation est souvent simple.
sudo apt update
sudo apt install -y ansible
ansible --version
Sur d’autres environnements, on peut utiliser pip, mais dans beaucoup de cas, le gestionnaire de paquets natif suffit. L’important est surtout de disposer d’une version stable et adaptée à votre environnement.
Dès que l’installation est terminée, il est utile de vérifier la configuration de base et de préparer un répertoire de projet propre. Un bon projet Ansible commence rarement par un seul fichier dispersé sur le bureau. Il commence plutôt par une arborescence claire, un inventaire organisé et une logique de séparation entre code, variables et fichiers de configuration.
Préparer un inventaire pour plusieurs serveurs
L’inventaire est l’un des piliers d’Ansible. C’est lui qui dit à Ansible où se trouvent vos serveurs et comment les regrouper. Dans sa forme la plus simple, il peut s’agir d’un fichier texte.
[web]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11
[db]
db01 ansible_host=192.168.1.20
[monitoring]
mon01 ansible_host=192.168.1.30
Avec un tel inventaire, vous pouvez cibler un groupe entier ou une seule machine. Cela devient très pratique lorsque vous voulez appliquer une mise à jour sur les serveurs web, configurer un cluster de base de données ou déployer un agent de supervision.
L’inventaire peut aussi contenir des paramètres de connexion :
[web]
web01 ansible_host=192.168.1.10 ansible_user=ubuntu
web02 ansible_host=192.168.1.11 ansible_user=ubuntu
[db]
db01 ansible_host=192.168.1.20 ansible_user=admin
Dans des environnements plus avancés, on utilise un inventaire au format YAML, ou même un inventaire dynamique, notamment dans le cloud. Mais pour bien démarrer, l’essentiel est de comprendre la logique de regroupement. Vous devez pouvoir répondre à des questions simples : quels serveurs appartiennent à quel rôle ? quelles variables sont communes ? quelles machines ont des spécificités ? quelles opérations doivent être appliquées à l’ensemble du parc, et lesquelles doivent rester ciblées ?
Tester la connexion avant d’aller plus loin
Avant de lancer le moindre playbook, il est toujours prudent de tester la connectivité.
ansible all -i inventory.ini -m ping
Si tout est correctement configuré, Ansible doit répondre pour chaque machine. Ce test simple permet de vérifier non seulement l’accès réseau, mais aussi les clés SSH, les droits de connexion et la bonne structure de l’inventaire.
Vous pouvez également cibler un groupe précis :
ansible web -i inventory.ini -m ping
Cela paraît anodin, mais ce type de vérification évite beaucoup de frustration. Lorsqu’un playbook échoue plus tard, on ne sait pas toujours si le problème vient du code, de l’inventaire, d’un mot de passe, d’une clé SSH ou d’un pare-feu. Mieux vaut isoler les problèmes tôt.
Écrire votre premier playbook multi-serveurs
Le playbook est le cœur de votre automatisation. C’est un fichier YAML qui décrit les actions à exécuter sur une ou plusieurs machines. Voici un exemple très simple :
---
- name: Préparer les serveurs web
hosts: web
become: true
tasks:
- name: Mettre à jour le cache APT
apt:
update_cache: yes
- name: Installer Nginx
apt:
name: nginx
state: present
- name: S'assurer que Nginx est démarré
service:
name: nginx
state: started
enabled: true
Ce playbook cible le groupe web, élève les privilèges avec become: true, met à jour le cache des paquets, installe Nginx, puis s’assure que le service tourne au démarrage.
Sur plusieurs serveurs, cette approche devient extrêmement puissante. Une seule exécution applique la même logique à tout le groupe. Vous pouvez ajouter des serveurs au groupe sans réécrire votre playbook. Vous gagnez en souplesse et en lisibilité.
Comprendre l’idempotence avec un exemple concret
L’un des grands avantages d’Ansible est son comportement idempotent. Prenons un exemple avec la création d’un fichier de configuration.
---
- name: Déployer une configuration simple
hosts: web
become: true
tasks:
- name: Copier une page HTML de test
copy:
dest: /var/www/html/index.html
content: "<h1>Serveur configuré avec Ansible</h1>"
owner: www-data
group: www-data
mode: "0644"
Si vous exécutez ce playbook une première fois, Ansible crée le fichier. Si vous le rejouez sans modifier le contenu, Ansible constate que l’état souhaité est déjà atteint. Il ne refait pas l’opération inutilement. C’est une manière plus fiable d’opérer à grande échelle.
Quand on gère plusieurs serveurs, cette propriété évite les surprises. On peut lancer un playbook de manière régulière, ou l’intégrer à une pipeline CI/CD, sans craindre de réécrire sans cesse les mêmes fichiers ou de provoquer des changements non désirés.
Organiser son projet avec des rôles
Dès que le projet grandit, il faut penser en rôles. Les rôles permettent de structurer les tâches, les variables, les templates, les fichiers statiques et les handlers dans une architecture claire.
Une arborescence classique peut ressembler à cela :
project-ansible/
├── inventory.ini
├── site.yml
├── group_vars/
│ ├── all.yml
│ └── web.yml
└── roles/
├── common/
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ └── templates/
└── nginx/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
└── templates/
└── nginx.conf.j2
Les rôles sont précieux parce qu’ils rendent votre code réutilisable. Le rôle common peut s’occuper des tâches communes à tous les serveurs, comme l’installation de paquets de base, la configuration du fuseau horaire ou la création d’utilisateurs. Le rôle nginx peut gérer tout ce qui concerne Nginx. Le rôle database peut faire la même chose pour MariaDB ou PostgreSQL.
Cette séparation est particulièrement utile quand vous gérez plusieurs serveurs ayant des responsabilités différentes. Elle évite de mélanger les préoccupations et améliore la compréhension globale du projet.
Exemple de rôle pour préparer tous les serveurs
Dans le rôle common, on peut par exemple installer quelques utilitaires utiles partout.
---
- name: Installer des paquets de base
apt:
name:
- curl
- vim
- htop
- unzip
state: present
update_cache: yes
- name: Créer un utilisateur de déploiement
user:
name: deploy
shell: /bin/bash
groups: sudo
append: yes
Puis dans un playbook principal :
---
- name: Configurer tous les serveurs
hosts: all
become: true
roles:
- common
Avec cette organisation, vous appliquez les fondations à l’ensemble du parc, puis vous spécialisez chaque groupe via des rôles additionnels.
Utiliser des variables pour adapter les serveurs
Les variables permettent de rendre vos playbooks flexibles. Sans variables, vous seriez obligé de dupliquer le code pour chaque environnement ou chaque groupe de serveurs. Avec elles, vous pouvez écrire une logique générique et injecter les différences au bon endroit.
Par exemple, le port d’écoute de Nginx peut varier selon l’environnement :
# group_vars/web.yml
nginx_port: 80
server_name: example.com
Puis dans un template :
server {
listen {{ nginx_port }};
server_name {{ server_name }};
root /var/www/html;
index index.html index.htm;
}
Le même fichier de template peut donc être utilisé partout, avec un rendu différent selon la machine ou le groupe ciblé. C’est simple, puissant et très lisible.
Ansible permet plusieurs niveaux de variables : globales, par groupe, par hôte, via la ligne de commande, via les playbooks, ou encore dans des fichiers chiffrés. La bonne pratique consiste à choisir un niveau de portée logique. Les valeurs communes vont dans group_vars/all.yml, les spécificités du groupe vont dans group_vars/web.yml, et les exceptions très ponctuelles peuvent être mises dans host_vars.
Déployer des fichiers de configuration avec les templates Jinja2
Les templates Jinja2 sont l’un des outils les plus utiles d’Ansible. Ils permettent de générer des fichiers de configuration dynamiques à partir de variables.
Voici un exemple de template pour Nginx :
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
}
http {
server_tokens off;
include /etc/nginx/mime.types;
server {
listen {{ nginx_port }};
server_name {{ server_name }};
location / {
root /var/www/html;
index index.html index.htm;
}
}
}
Et dans le rôle :
---
- name: Installer Nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Déployer la configuration Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Redémarrer Nginx
- name: S'assurer que Nginx est actif
service:
name: nginx
state: started
enabled: true
Le handler associé :
---
- name: Redémarrer Nginx
service:
name: nginx
state: restarted
L’intérêt du handler est essentiel. On ne redémarre Nginx que si la configuration a changé. Cela évite les interruptions inutiles et rend l’automatisation plus intelligente.
Gérer plusieurs environnements sans dupliquer le code
Dans la vraie vie, on a rarement un seul environnement. Il y a presque toujours un environnement de développement, de recette, de préproduction et de production. Si l’on duplique les fichiers pour chaque environnement, on finit par perdre la cohérence. Il faut au contraire garder la logique commune et ne varier que ce qui doit l’être.
Un bon schéma consiste à créer des groupes distincts :
[web_dev]
web-dev-01 ansible_host=10.0.10.11
[web_prod]
web-prod-01 ansible_host=10.0.20.11
web-prod-02 ansible_host=10.0.20.12
Puis des fichiers de variables adaptés :
# group_vars/web_dev.yml
nginx_port: 8080
server_name: dev.example.local
# group_vars/web_prod.yml
nginx_port: 80
server_name: example.com
Le même playbook peut alors être réutilisé partout sans modification majeure. Vous changez seulement le groupe ciblé. Cette discipline évite les erreurs de copie et les divergences involontaires entre environnements.
Utiliser les handlers pour agir au bon moment
Les handlers sont une petite merveille d’élégance. Ils permettent de déclencher une action uniquement lorsqu’un changement a réellement eu lieu. Par exemple, si vous modifiez un fichier de configuration Apache ou Nginx, vous pouvez demander un redémarrage du service. Mais si le fichier n’a pas changé, aucun redémarrage n’est nécessaire.
Exemple :
---
- name: Déployer la configuration Apache
template:
src: apache.conf.j2
dest: /etc/apache2/sites-available/000-default.conf
notify: Redémarrer Apache
---
- name: Redémarrer Apache
service:
name: apache2
state: restarted
Ce mécanisme apporte une finesse très pratique. Quand on gère plusieurs serveurs, éviter les redémarrages inutiles améliore la stabilité, réduit les coupures et limite le risque de perturbation.
Automatiser une application web complète
Prenons maintenant un exemple plus concret. Imaginons que vous souhaitez déployer une application web sur plusieurs serveurs. Vous voulez installer les dépendances, copier les fichiers, déployer la configuration et assurer le démarrage du service.
Un playbook simplifié peut ressembler à cela :
---
- name: Déployer l'application web
hosts: web
become: true
vars:
app_dir: /var/www/myapp
tasks:
- name: Installer Nginx et Python
apt:
name:
- nginx
- python3
- python3-venv
state: present
update_cache: yes
- name: Créer le répertoire de l'application
file:
path: "{{ app_dir }}"
state: directory
owner: www-data
group: www-data
mode: "0755"
- name: Copier les fichiers de l'application
copy:
src: ./app/
dest: "{{ app_dir }}/"
owner: www-data
group: www-data
mode: preserve
- name: Déployer la configuration du site
template:
src: site.conf.j2
dest: /etc/nginx/sites-available/myapp.conf
notify: Redémarrer Nginx
- name: Activer le site
file:
src: /etc/nginx/sites-available/myapp.conf
dest: /etc/nginx/sites-enabled/myapp.conf
state: link
notify: Redémarrer Nginx
- name: S'assurer que Nginx démarre au boot
service:
name: nginx
state: started
enabled: true
handlers:
- name: Redémarrer Nginx
service:
name: nginx
state: restarted
Cet exemple montre très bien la logique d’ensemble. Avec quelques tâches bien organisées, vous automatisez l’installation, la copie des fichiers, la configuration du reverse proxy et la gestion du service. Multipliez cela par plusieurs serveurs, et vous mesurez immédiatement le gain de temps.
Faire des déploiements sélectifs avec les tags
Dans les projets plus grands, il est pratique de pouvoir exécuter seulement une partie d’un playbook. Les tags permettent cela. Vous pouvez taguer certaines tâches pour lancer uniquement ce qui vous intéresse.
---
- name: Déployer le serveur web
hosts: web
become: true
tasks:
- name: Installer Nginx
apt:
name: nginx
state: present
tags:
- packages
- name: Déployer la configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- config
- name: Redémarrer Nginx
service:
name: nginx
state: restarted
tags:
- service
Puis :
ansible-playbook -i inventory.ini site.yml --tags config
Cette méthode est utile lorsque vous voulez ajuster seulement une configuration sans toucher aux paquets, ou inversement. Dans un parc avec plusieurs serveurs, cela rend les interventions beaucoup plus ciblées.
Réussir la gestion des utilisateurs et des permissions
L’administration de plusieurs serveurs ne se limite pas aux services web. Il faut aussi penser aux comptes utilisateurs, aux clés SSH, aux droits d’accès et aux permissions des fichiers. Ansible excelle là encore.
Créer plusieurs utilisateurs devient simple :
---
- name: Créer des utilisateurs techniques
hosts: all
become: true
tasks:
- name: Ajouter l'utilisateur deploy
user:
name: deploy
shell: /bin/bash
groups: sudo
append: yes
- name: Installer la clé SSH
authorized_key:
user: deploy
key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC..."
Cela évite de refaire manuellement les mêmes actions sur chaque machine. Vous pouvez créer une politique cohérente de sécurité et de gestion d’accès. C’est beaucoup plus propre qu’une succession d’interventions ponctuelles par SSH.
Chiffrer les données sensibles avec Ansible Vault
Dès qu’un projet Ansible devient sérieux, la question des secrets se pose. Mots de passe, clés API, certificats, identifiants de base de données : tous ces éléments ne doivent pas circuler en clair dans un dépôt Git.
Ansible Vault permet de chiffrer ce type de données.
ansible-vault create group_vars/web/vault.yml
Dans le fichier chiffré, vous pouvez stocker par exemple :
db_password: supersecretpassword
api_token: verysecretvalue
Puis dans votre playbook :
- name: Configurer l'application
hosts: web
vars_files:
- group_vars/web/vault.yml
tasks:
- name: Créer le fichier de configuration
template:
src: app.conf.j2
dest: /etc/myapp/app.conf
Au moment de l’exécution, vous fournirez le mot de passe Vault. Cela permet de sécuriser votre automatisation sans sacrifier la lisibilité du projet.
Gérer des centaines de serveurs sans perdre le contrôle
Quand on passe de quelques serveurs à des dizaines, puis à des centaines, la difficulté n’est plus seulement technique. Elle devient organisationnelle. Il faut une structure claire, des conventions de nommage, une gestion propre des variables, une séparation nette entre les rôles et une discipline dans les changements.
Dans ce contexte, quelques habitudes font une vraie différence.
D’abord, gardez vos playbooks courts et composés de rôles. Un rôle doit faire une chose, et la faire bien. Ensuite, factorisez les variables. Un réglage ne doit pas être dupliqué dans cinq fichiers. Enfin, testez régulièrement vos automatisations dans un environnement de préproduction avant toute application large.
La lecture du code doit rester simple. Quand un collègue ouvre le projet, il doit pouvoir comprendre rapidement ce qui se passe. Si la structure est trop complexe, l’outil perd une partie de sa valeur. L’automatisation doit rendre les choses plus claires, pas plus opaques.
Les bonnes pratiques à adopter dès le début
Pour éviter de construire une base fragile, mieux vaut adopter quelques réflexes dès le départ.
Évitez les fichiers trop longs. Préférez les rôles. Évitez de mettre des variables en dur dans le corps des tâches quand elles peuvent être externalisées. Évitez de mélanger configuration système, déploiement applicatif et logique métier dans un seul playbook. Évitez également d’utiliser command ou shell à tout-va alors qu’un module Ansible existe déjà. Les modules dédiés sont plus sûrs, plus lisibles et plus idempotents.
Il est aussi recommandé de versionner votre projet dans Git. Cela paraît évident, mais ce point est fondamental. Chaque modification d’infrastructure doit pouvoir être suivie, relue et éventuellement revertie. C’est une discipline qui apporte une grande tranquillité d’esprit.
Enfin, testez systématiquement vos playbooks sur un petit périmètre avant de les lancer sur toute la flotte. Même un fichier très propre peut contenir une mauvaise hypothèse. Quelques machines pilotes permettent de valider le comportement réel sans risque excessif.
Exécuter des tâches de manière parallèle et ciblée
L’un des avantages pratiques d’Ansible est sa capacité à agir sur plusieurs machines en parallèle. Cela accélère énormément les opérations répétitives. Vous pouvez aussi cibler un sous-ensemble précis.
Par exemple :
ansible-playbook -i inventory.ini site.yml --limit web01
Cela permet de tester une modification sur un seul serveur avant de généraliser. Vous pouvez aussi limiter à un groupe :
ansible-playbook -i inventory.ini site.yml --limit web
Ou encore à plusieurs groupes selon votre inventaire. Cette granularité est très utile lorsque vous devez gérer un parc hétérogène. Elle vous donne le contrôle sans sacrifier la vitesse.
Utiliser les boucles pour réduire la répétition
Les boucles sont très utiles lorsqu’il faut appliquer la même logique à plusieurs éléments. Par exemple, installer une liste de paquets :
---
- name: Installer des paquets utiles
hosts: all
become: true
tasks:
- name: Installer la liste de paquets
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop:
- curl
- git
- vim
- htop
Plutôt que dupliquer quatre tâches similaires, vous exprimez une intention claire et concise. Dans des configurations plus avancées, les boucles peuvent aussi servir à créer plusieurs utilisateurs, plusieurs répertoires ou plusieurs règles de pare-feu.
Contrôler les services système de façon fiable
L’administration de plusieurs serveurs implique souvent de gérer systemd et les services associés. Ansible propose des modules adaptés qui sont bien meilleurs qu’un script artisanal.
---
- name: Contrôler un service système
hosts: all
become: true
tasks:
- name: Arrêter un service si nécessaire
service:
name: cron
state: stopped
- name: Redémarrer un service
service:
name: rsyslog
state: restarted
Ces actions sont simples, mais elles jouent un rôle majeur dans les déploiements, les mises à jour et les opérations de maintenance. Là encore, le fait de pouvoir les appliquer à plusieurs serveurs avec le même code change totalement l’expérience.
Surveiller les changements et comprendre ce qu’Ansible a fait
Quand on lance un playbook, il est important de savoir ce qui a changé. Ansible fournit un retour clair sur les tâches exécutées. Vous voyez ce qui a été modifié, ce qui est resté inchangé, et ce qui a échoué. Cette visibilité est précieuse.
Dans un environnement réel, il est recommandé de lire attentivement les résultats d’exécution. Une tâche marquée comme “changed” indique qu’Ansible a appliqué une modification. Une tâche “ok” signifie que tout était déjà en place. Une tâche “failed” demande une intervention. Cette granularité facilite le diagnostic.
Vous pouvez également augmenter la verbosité :
ansible-playbook -i inventory.ini site.yml -v
ou
ansible-playbook -i inventory.ini site.yml -vvv
Cela peut être utile en phase de débogage, notamment si une connexion SSH, un template ou une variable pose problème.
Éviter les pièges les plus fréquents
Même si Ansible est relativement simple à prendre en main, certaines erreurs reviennent souvent.
La première est de tout faire dans un seul playbook. Cela devient vite illisible. La deuxième est de multiplier les shell et command sans raison. La troisième est de ne pas structurer les variables proprement. La quatrième est de modifier directement la production sans validation préalable. La cinquième est d’ignorer la documentation et les conventions de nommage.
Il y a aussi un piège psychologique : parce qu’Ansible rend l’automatisation facile, on peut être tenté d’ajouter toujours plus de logique. Il faut parfois savoir rester simple. Un bon playbook n’est pas celui qui fait le plus de choses. C’est celui qui fait les bonnes choses de façon claire, fiable et maintenable.
Exemple d’une architecture Ansible plus réaliste
Voici une organisation souvent très efficace pour un projet de taille moyenne à importante :
ansible-project/
├── inventories/
│ ├── dev/
│ │ └── hosts.ini
│ ├── staging/
│ │ └── hosts.ini
│ └── prod/
│ └── hosts.ini
├── group_vars/
│ ├── all.yml
│ ├── web.yml
│ └── db.yml
├── host_vars/
│ └── web01.yml
├── roles/
│ ├── common/
│ ├── nginx/
│ ├── app/
│ └── postgres/
├── playbooks/
│ ├── site.yml
│ ├── web.yml
│ └── db.yml
└── ansible.cfg
Avec une telle architecture, vous savez où chercher quoi. Les inventaires sont séparés par environnement. Les variables sont rangées selon leur portée. Les rôles sont réutilisables. Les playbooks sont légers et ciblés. Cette lisibilité devient un énorme atout quand l’équipe grandit.
Exemple d’un fichier ansible.cfg utile
Un fichier de configuration peut simplifier vos commandes quotidiennes.
[defaults]
inventory = inventories/dev/hosts.ini
remote_user = ubuntu
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
interpreter_python = auto_silent
[privilege_escalation]
become = True
Ce genre de configuration évite de répéter les mêmes options à chaque exécution. Vous pouvez bien sûr l’adapter à votre organisation, mais il est souvent utile de centraliser les paramètres courants.
Quand Ansible devient vraiment confortable
Il y a un moment, dans l’usage d’Ansible, où l’on cesse de le percevoir comme un simple outil et où il devient une manière de travailler. Ce moment arrive quand on ne se demande plus “comment vais-je configurer ce serveur ?” mais plutôt “quelle est la description correcte de cet état dans mon projet Ansible ?”.
Cette bascule est importante. Elle transforme l’administration au quotidien. On passe d’un geste manuel à une intention codifiée. On évite le bricolage, on améliore la traçabilité, et l’on crée une base commune pour l’équipe. Cette base réduit les écarts entre les serveurs, facilite les audits et accélère les nouvelles mises en production.
La vraie force d’Ansible n’est pas seulement d’automatiser. C’est d’unifier la manière dont on pense l’infrastructure. Une fois que cette idée est intégrée, gérer plusieurs serveurs devient beaucoup plus calme.
Exemple complet : préparer plusieurs serveurs web
Voici un exemple plus complet, volontairement proche d’un cas réel.
---
- name: Préparer les serveurs web
hosts: web
become: true
vars:
app_dir: /var/www/myapp
nginx_conf_path: /etc/nginx/sites-available/myapp.conf
tasks:
- name: Installer les paquets requis
apt:
name:
- nginx
- git
- curl
state: present
update_cache: yes
- name: Créer l'utilisateur deploy
user:
name: deploy
shell: /bin/bash
groups: sudo
append: yes
- name: Créer le répertoire de l'application
file:
path: "{{ app_dir }}"
state: directory
owner: www-data
group: www-data
mode: "0755"
- name: Déployer l'application
copy:
src: ./app/
dest: "{{ app_dir }}/"
owner: www-data
group: www-data
mode: preserve
- name: Générer la configuration Nginx
template:
src: myapp.nginx.j2
dest: "{{ nginx_conf_path }}"
notify: Redémarrer Nginx
- name: Activer le site
file:
src: "{{ nginx_conf_path }}"
dest: /etc/nginx/sites-enabled/myapp.conf
state: link
notify: Redémarrer Nginx
- name: Vérifier que Nginx est démarré
service:
name: nginx
state: started
enabled: true
handlers:
- name: Redémarrer Nginx
service:
name: nginx
state: restarted
Ce type de playbook est déjà très utile dans une équipe DevOps ou dans une petite entreprise qui veut standardiser ses déploiements. Il est clair, extensible et lisible. On peut facilement l’enrichir avec des variables par environnement, des templates supplémentaires et des conditions.
Ajouter des conditions pour plus de finesse
Les conditions permettent d’adapter l’exécution selon un contexte. Par exemple, vous pouvez installer un paquet seulement si le système est Debian, ou lancer une tâche seulement sur un groupe particulier.
---
- name: Appliquer une tâche conditionnelle
hosts: all
become: true
tasks:
- name: Installer un paquet uniquement sur Debian
apt:
name: htop
state: present
when: ansible_os_family == "Debian"
Dans un parc hétérogène, cette capacité est très utile. Elle évite d’écrire des playbooks séparés pour chaque famille de système, tout en conservant de la précision.
Conserver une logique humaine dans l’automatisation
Il est facile, en automatisant beaucoup, de perdre la dimension humaine du travail. Pourtant, la qualité d’un bon projet Ansible tient aussi à son intelligibilité. Un bon playbook raconte quelque chose. Il est compréhensible, presque narratif. On y lit une intention claire : préparer l’environnement, installer les dépendances, appliquer la configuration, redémarrer si nécessaire, vérifier l’état final.
Cette lisibilité est précieuse pour les personnes qui reprendront le projet plus tard. Elle est aussi très utile lorsqu’un incident survient et qu’il faut comprendre rapidement ce qui a été appliqué. Le but n’est pas seulement de faire marcher les serveurs. Le but est de pouvoir les faire évoluer sans peur.
Conclusion
Gérer plusieurs serveurs avec Ansible facilement n’a rien de magique. C’est le résultat d’une méthode simple mais solide : décrire l’état souhaité de vos machines, structurer le projet proprement, séparer les responsabilités avec des rôles, externaliser les variables, utiliser les templates pour les configurations dynamiques, et faire confiance à l’idempotence pour maintenir la cohérence au fil du temps.
Ce qui semble au départ être un outil d’automatisation devient rapidement un vrai cadre de travail. On gagne du temps, on réduit les erreurs humaines, on simplifie les déploiements et on rend l’infrastructure beaucoup plus lisible. Plus le nombre de serveurs augmente, plus cette discipline prend de la valeur. C’est là que l’on comprend qu’Ansible n’est pas seulement pratique. Il est rassurant.