1. Organiser et nommer #
Lisible par toute l'équipe.
Structure du dépôt #
infra/
├── ansible.cfg
├── requirements.yml # collections et rôles épinglés
├── inventories/{dev,preprod,prod}/{hosts.yml,group_vars/,host_vars/}
├── playbooks/*.yml
├── roles/<composant>/{tasks,handlers,defaults,templates,meta}
└── .ansible-lint, .yamllint, .gitlab-ci.yml- Une tâche = un
nameexplicite décrivant le résultat (« Installer nginx », pas « task 1 »). - Utilisez les noms complets FQCN :
ansible.builtin.apt,community.general.ufw. - Préfixez les variables d'un rôle par son nom (
nginx_port) ; valeurs par défaut dansdefaults/. - Un inventaire par environnement ; ne dupliquez pas le code, seulement les données (
group_vars).
2. Idempotence et modules #
Décrire l'état souhaité.
Éviter shell et command #
# ❌ Non idempotent, aucun contrôle d'état
- ansible.builtin.shell: apt-get install -y nginx && systemctl enable nginx
# ✅ Modules d'état
- ansible.builtin.apt: { name: nginx, state: present, update_cache: true, cache_valid_time: 3600 }
- ansible.builtin.service: { name: nginx, state: started, enabled: true }
# Si command/shell est inévitable : rendre le résultat fiable
- name: Initialiser la base
ansible.builtin.command: /opt/app/init-db.sh
args: { creates: /var/lib/app/.initialized } # ne s'exécute qu'une fois
- name: Lire la version
ansible.builtin.command: app --version
register: version
changed_when: false # une lecture ne modifie rienansible-playbook site.yml --check --diff # simulation
ansible-playbook site.yml # 1re exécution : changed
ansible-playbook site.yml # 2e exécution : changed=0 (idempotent)Bonne Pratique : Un playbook idempotent affiche changed=0 au second passage. Faites de ce critère un test automatique dans la CI (Molecule le vérifie).3. Sécurité #
Secrets et privilèges.
Les essentiels #
# Secrets chiffrés + masqués
ansible-vault encrypt_string 'S3cr3t!' --name vault_db_password
- ansible.builtin.template: { src: app.env.j2, dest: /etc/app/app.env, mode: "0600", owner: app }
no_log: true
# Privilèges ciblés : become uniquement où nécessaire
- hosts: webservers
tasks:
- ansible.builtin.copy: { src: motd, dest: /etc/motd }
become: true- Clés SSH dédiées (
ed25519),host_key_checking = True, pas de mot de passe en clair. - Épinglez les versions de collections et rôles (
requirements.yml) pour des exécutions reproductibles. - Jamais de secret dans Git en clair ni dans les logs de CI.
4. Qualité et performance #
Linter, tester, mesurer.
Outils #
ansible-lint --profile production # profils : min, basic, moderate, safety, shared, production
yamllint . && ansible-playbook site.yml --syntax-check
molecule test # create, converge, idempotence, verify, destroy
# ansible.cfg : performance
[defaults]
forks = 30
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/facts
callbacks_enabled = profile_tasks
[ssh_connection]
pipelining = True| Anti-pattern | Alternative |
|---|---|
ignore_errors: true partout | failed_when / block-rescue ciblés |
| Variables définies à 5 endroits | Une source par variable (group_vars) et précédence connue |
| Rôle « fourre-tout » de 500 lignes | Rôles courts, un composant chacun |
| Handlers jamais testés | --check et Molecule sur les chemins de notification |
| Mot de passe sudo en clair | Sudo sans mot de passe limité ou --ask-become-pass |
Schéma de référence et vérification rapide #
Visualiser le principe et le contrôler en ligne de commande.
Schéma de référence #
ansible-lint && molecule test && ansible-playbook site.yml --check --diff