infra / linux-bash
Automatisation avec Ansible (niveau expert)
Explication
Ce que vous allez apprendre
- Comprendre pourquoi gérer un parc de serveurs à la main en SSH ne passe pas à l'échelle
- Distinguer l'approche déclarative d'Ansible de l'approche impérative d'un script bash
- Comprendre le fonctionnement "agentless" d'Ansible, basé uniquement sur SSH
- Organiser un inventaire de serveurs par groupes de rôles (
[web],[db]) - Toujours valider un playbook avec
--check --diffavant de le lancer en production
Dans quel contexte ?
Tu dois installer une mise à jour de sécurité nginx sur 12 serveurs web avant ce soir. Te connecter un par un en SSH pour taper la même commande douze fois prend du temps et risque l'oubli d'un serveur — c'est exactement le problème qu'Ansible résout.
D'abord, le problème très concret qu'Ansible résout
Gérer dix serveurs en se connectant un par un en SSH pour taper les mêmes commandes ne passe pas à l'échelle : un serveur oublié, une commande tapée différemment, et le parc devient incohérent. Ansible décrit une seule fois l'état voulu et l'applique identiquement sur tous les serveurs concernés.
Ensuite, il faut comprendre une différence fondamentale avec un script bash
Un script bash décrit une suite d'étapes ("installe ceci, puis fais cela"). Un playbook Ansible décrit un état final voulu ("ce paquet doit être présent", "ce service doit être actif") : Ansible compare l'état actuel à l'état voulu et n'agit que si nécessaire, ce qui le rend idempotent sans effort particulier.
| Approche | Exemple | Si l'état voulu existe déjà |
|---|---|---|
| Script bash (impératif) | apt install nginx | Réinstalle ou ne fait rien selon le paquet |
| Playbook Ansible (déclaratif) | apt: name=nginx state=present | Ne touche à rien, constat "déjà conforme" |
Une fois ce principe posé, comment Ansible se connecte-t-il aux machines
Contrairement à d'autres outils qui nécessitent d'installer un agent permanent sur chaque serveur géré, Ansible se contente d'une connexion SSH classique déjà en place. C'est ce qui rend le déploiement initial très simple : si ssh web1.exemple.com fonctionne déjà, Ansible fonctionne.
Il reste une question d'organisation : comment cibler un groupe précis de machines
Un fichier inventory.ini regroupe les serveurs par rôle, comme [web] et [db], ce qui permet une commande comme ansible web -i inventory.ini -a "systemctl status nginx" sans lister chaque machine individuellement.
Prérequis
Ansible suppose que ssh utilisateur@serveur fonctionne déjà sans mot de passe interactif (clé SSH en place). Si ce n'est pas le cas, règle d'abord l'accès SSH avant de toucher à Ansible.
Maintenant, regardons un playbook réel
Une tâche comme apt: name: ["python3-venv", "nginx"] state: present installe un paquet seulement s'il n'est pas déjà présent. La directive notify: redémarrer mon-app déclenche un handler uniquement si la tâche a réellement changé quelque chose, évitant un redémarrage inutile du service.
Le piège à connaître avant de déployer pour de vrai
Lancer un playbook directement en production sans --check --diff d'abord revient à sauter l'étape de vérification qu'un dry-run t'offrait pourtant gratuitement. ansible-playbook deploy.yml --check --diff montre exactement ce qui va changer, sans rien modifier. Ansible s'appuie sur tout ce que tu as appris jusqu'ici — SSH, systemd, gestion de paquets — pour l'orchestrer à grande échelle ; la prochaine leçon retourne au niveau le plus bas, celui du noyau, en montrant comment Docker isole un processus sans qu'aucune magie n'entre en jeu.
Commandes & code
Automatisation avec Ansible
# inventory.ini : décrit les machines cibles, regroupées logiquement
[web]
web1.exemple.com
web2.exemple.com ansible_port=2222
[db]
db1.exemple.com ansible_user=admin
[prod:children]
web
db
[prod:vars]
ansible_ssh_private_key_file=~/.ssh/cle_prod# Vérifier la connectivité avant tout playbook
ansible prod -i inventory.ini -m ping
# Exécuter une commande ad-hoc sur un groupe sans écrire de playbook
ansible web -i inventory.ini -a "systemctl status nginx" --become
ansible prod -i inventory.ini -m shell -a "df -h" --become
# Lancer un playbook complet
ansible-playbook -i inventory.ini deploy.yml
ansible-playbook -i inventory.ini deploy.yml --check # dry-run, ne modifie rien
ansible-playbook -i inventory.ini deploy.yml --diff # montre les changements de fichiers
ansible-playbook -i inventory.ini deploy.yml --limit web1 # limite à une seule machine
ansible-playbook -i inventory.ini deploy.yml -e "version=1.4.2" # variable passée en ligne de commande# deploy.yml : playbook idempotent de déploiement d'une API
---
- name: Déployer l'API backend
hosts: web
become: true
vars:
app_version: "{{ version | default('latest') }}"
app_dir: /opt/mon-app
tasks:
- name: Installer les dépendances système
apt:
name: ["python3-venv", "nginx"]
state: present
update_cache: true
- name: Créer l'utilisateur applicatif
user:
name: deploy
system: true
shell: /usr/sbin/nologin
- name: Déployer l'archive de la release
unarchive:
src: "https://registry.exemple.com/mon-app/{{ app_version }}.tar.gz"
dest: "{{ app_dir }}"
remote_src: true
notify: redémarrer mon-app
- name: Déployer le fichier de service systemd
template:
src: templates/mon-app.service.j2
dest: /etc/systemd/system/mon-app.service
mode: "0644"
notify:
- recharger systemd
- redémarrer mon-app
- name: Vérifier que le service est actif
systemd:
name: mon-app
enabled: true
state: started
handlers:
- name: recharger systemd
systemd:
daemon_reload: true
- name: redémarrer mon-app
systemd:
name: mon-app
state: restarted# templates/mon-app.service.j2 : template Jinja2, {{ }} injecte des variables Ansible
[Unit]
Description=API backend ({{ app_version }})
After=network.target
[Service]
User=deploy
WorkingDirectory={{ app_dir }}
ExecStart={{ app_dir }}/venv/bin/uvicorn app.main:app --port 8000
Restart=on-failure
[Install]
WantedBy=multi-user.target# Roles : structure recommandée pour un projet Ansible qui grossit
# roles/webserver/tasks/main.yml, roles/webserver/handlers/main.yml, roles/webserver/templates/...
ansible-galaxy init roles/webserver
# Chiffrer les secrets (mots de passe, clés API) directement dans le repo git
ansible-vault create group_vars/prod/secrets.yml
ansible-vault edit group_vars/prod/secrets.yml
ansible-playbook -i inventory.ini deploy.yml --ask-vault-passRésumé
- Ansible est agentless (SSH uniquement) et déclaratif : on décrit l'état voulu, pas les étapes.
--check --diffavant tout déploiement réel ;handlersévitent un redémarrage inutile si rien n'a changé.ansible-vaultchiffre les secrets pour qu'ils puissent vivre dans le même repo git que le reste de l'infra.
Exercices pratiques
Mission : déployer une mise à jour de sécurité sur 12 serveurs
Objectif : Utiliser Ansible de façon déclarative et prudente pour appliquer un correctif nginx à l'échelle sans risque.
Contexte
Tu dois installer une mise à jour de sécurité nginx sur 12 serveurs web avant ce soir. Te connecter un par un en SSH prendrait trop de temps et risquerait un oubli. Ansible doit appliquer ce correctif de façon identique et vérifiable sur tout le groupe [web].