Passer au contenu principal

Production (Ansible)

Bonnes pratiques

Les bonnes pratiques Ansible ne sont pas des conventions arbitraires. Elles répondent à des problèmes réels : playbooks qui cassent en prod, debugging de 3h pour une variable surchargée, rôle non réutilisable parce qu'il hardcode ses valeurs. Ce qui suit est tiré de l'expérience terrain.

Nommer toutes les tâches

Une tâche sans name est illisible dans les logs et impossible à retrouver dans un playbook de 200 lignes. Le nom doit être descriptif et refléter l'intention, pas la mécanique :

# Mauvais
- ansible.builtin.apt:
    name: nginx
    state: present

# Bon
- name: Installer nginx
  ansible.builtin.apt:
    name: nginx
    state: present

# Encore mieux (contexte + action)
- name: Installer nginx (serveur web principal)
  ansible.builtin.apt:
    name: nginx
    state: present

Utiliser les modules dédiés plutôt que command/shell

Chaque appel à command ou shell brise l'idempotence et rend le playbook plus fragile. Si un module existe, l'utiliser :

# Mauvais
- ansible.builtin.shell: "systemctl restart nginx"

# Bon
- ansible.builtin.systemd:
    name: nginx
    state: restarted

# Mauvais
- ansible.builtin.shell: "useradd -m -s /bin/bash appuser"

# Bon
- ansible.builtin.user:
    name: appuser
    shell: /bin/bash
    create_home: true

Versionner les dépendances

Un requirements.yml sans versions est une bombe à retardement : la prochaine installation peut embarquer une version incompatible d'un rôle ou d'une collection.

# Mauvais
collections:
  - name: community.general

# Bon
collections:
  - name: community.general
    version: ">=7.0.0,<8.0.0"

Tags et --limit pour les déploiements partiels

# Tagguer les tâches par domaine fonctionnel
- name: Déployer la configuration nginx
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  tags:
    - nginx
    - config

- name: Déployer le code applicatif
  ansible.builtin.git:
    repo: https://github.com/example/myapp.git
    dest: /srv/myapp
  tags:
    - app
    - deploy
# Ne lancer que les tâches taguées "config"
ansible-playbook site.yml --tags config

# Exclure les tâches taguées "deploy"
ansible-playbook site.yml --skip-tags deploy

# Combiner avec --limit
ansible-playbook site.yml --tags nginx --limit web01.example.com

Tester l'idempotence systématiquement

Après chaque modification d'un playbook, relancer deux fois et vérifier que le second run donne changed=0. Si ce n'est pas le cas, identifier la tâche non idempotente et la corriger (avec changed_when, creates, ou en remplaçant le module shell par le bon module).

ansible-lint en pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/ansible/ansible-lint
    rev: v24.2.0
    hooks:
      - id: ansible-lint
        files: \.(yaml|yml)$
pip install pre-commit
pre-commit install

Ce qui casse en production

Les incidents Ansible en production ont généralement les mêmes causes :

  • Variable non définie sur un hôte particulier qui n'appartient pas au bon groupe
  • gather_facts désactivé et utilisation d'un fact comme ansible_distribution
  • Module shell non idempotent qui s'exécute à chaque run et crée des doublons
  • Handler non déclenché parce que la tâche était en ok et non changed
  • serial trop élevé : rolling update qui coupe trop d'hôtes simultanément
  • Vault password manquant en CI : le pipeline s'arrête sur tous les hôtes simultanément

La plupart de ces problèmes sont évités par des tests en staging avant la prod, et par --check --diff sur les changements critiques.