RousselTMLEARNING

Automatisation

Ansible : gérer son infrastructure avec des playbooks (Infrastructure as Code)

Écrire des playbooks de production : structure d'un projet, plays, handlers, tags, strategy serial, blocs de gestion d'erreurs, déploiement progressif et orchestration multi-tiers.

1. Organiser un projet Ansible #

De quelques fichiers à un dépôt industrialisé.

Structure de référence #

projet-infra/
├── ansible.cfg
├── requirements.yml
├── site.yml                 # point d'entrée : importe les playbooks
├── playbooks/
│   ├── loadbalancers.yml
│   ├── webservers.yml
│   └── dbservers.yml
├── inventories/
│   ├── lab/    {hosts.ini, group_vars/, host_vars/}
│   └── prod/   {hosts.ini, group_vars/, host_vars/}
└── roles/
    ├── common/  nginx/  haproxy/  postgresql/
# site.yml
- import_playbook: playbooks/dbservers.yml
- import_playbook: playbooks/webservers.yml
- import_playbook: playbooks/loadbalancers.yml
Orchestration multi-tiers avec Ansible
L'ordre des plays reflète les dépendances : base, applications, puis load balancer.

2. Un playbook de production #

Variables, handlers, tags et conditions.

Exemple complet #

# playbooks/webservers.yml
- name: Configurer les serveurs web
  hosts: webservers
  become: true
  gather_facts: true
  vars:
    app_version: "1.4.2"
  roles:
    - role: common
      tags: [common]
    - role: nginx
      tags: [nginx]

  pre_tasks:
    - name: Retirer le serveur du load balancer
      ansible.builtin.uri:
        url: "http://lb.lab:8404/disable/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

  tasks:
    - name: Déployer l'application
      ansible.builtin.unarchive:
        src: "https://artifacts.lab/app-{{ app_version }}.tgz"
        dest: /opt/app
        remote_src: true
      notify: Redémarrer l'application
      tags: [deploy]

  post_tasks:
    - name: Vérifier que l'application répond
      ansible.builtin.uri:
        url: "http://localhost:8080/health"
        status_code: 200
      retries: 10
      delay: 3
      register: health
      until: health.status == 200

  handlers:
    - name: Redémarrer l'application
      ansible.builtin.systemd:
        name: app
        state: restarted

Exécuter, simuler, cibler #

ansible-playbook site.yml --syntax-check
ansible-playbook site.yml --check --diff               # dry-run + différences
ansible-playbook site.yml -i inventories/prod --limit web1.lab
ansible-playbook site.yml --tags deploy
ansible-playbook site.yml --skip-tags common
ansible-playbook site.yml --start-at-task "Déployer l'application"
ansible-playbook site.yml -vvv                           # débogage détaillé
ansible-playbook site.yml --list-hosts --list-tasks

3. Déploiements progressifs et résilients #

serial, blocs et gestion des erreurs.

Rolling update avec serial #

- hosts: webservers
  serial: "25%"                 # ou 2, ou [1, 5, 10] pour des vagues croissantes
  max_fail_percentage: 10       # arrêter si plus de 10 % des hôtes échouent
  tasks:
    - name: Mettre à jour l'application
      ansible.builtin.package: { name: app, state: latest }
Bonne Pratique : Avec serial, les vagues se déroulent l'une après l'autre : une erreur sur la première vague empêche de propager un mauvais déploiement à toute la production.

block / rescue / always #

- name: Déploiement avec retour arrière
  block:
    - name: Appliquer la nouvelle version
      ansible.builtin.command: /opt/app/deploy.sh {{ app_version }}
    - name: Smoke test
      ansible.builtin.uri: { url: "http://localhost:8080/health" }
  rescue:
    - name: Restaurer la version précédente
      ansible.builtin.command: /opt/app/rollback.sh
    - name: Notifier l'équipe
      community.general.slack: { token: "{{ vault_slack_token }}", msg: "Déploiement échoué sur {{ inventory_hostname }}" }
      delegate_to: localhost
  always:
    - name: Journaliser l'opération
      ansible.builtin.lineinfile: { path: /var/log/deploys.log, line: "{{ ansible_date_time.iso8601 }} {{ app_version }}", create: true }

Délégation et exécution unique #

- name: Migrer le schéma (une seule fois pour tout le groupe)
  ansible.builtin.command: /opt/app/migrate.sh
  run_once: true
  delegate_to: "{{ groups['dbservers'][0] }}"

- name: Enregistrer le déploiement dans le CMDB
  ansible.builtin.uri: { url: "https://cmdb.lab/api/deployments", method: POST, body_format: json, body: { host: "{{ inventory_hostname }}" } }
  delegate_to: localhost
Erreur Courante : command et shell ne sont pas idempotents : ajoutez creates:, removes: ou changed_when: pour que le playbook reste rejouable.

Articles liés

Ansible : l'inventaire (statique, dynamique, groupes et variables)

Comprendre et maîtriser l'inventaire Ansible : fichiers INI et YAML, groupes, variables d'hôte et de groupe, …

Ansible : les commandes Ad-Hoc

Exécuter des actions immédiates sur un parc de serveurs avec ansible : modules ping, command, shell, copy, ap…

Ansible : structurer son code avec les rôles

Créer, organiser et réutiliser des rôles Ansible : arborescence, defaults, tasks, handlers, templates, dépend…

Pour aller plus loin

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !