Aller au contenu principal
AnsibleDevOpsAutomationInfrastructure as Code

Les Roles : organiser son code

30 min de lecture Ansible — Chapitre 3

Structure tes playbooks Ansible avec les Roles : convention de répertoires, création from scratch, handlers, defaults et bonnes pratiques.

🎯 Objectif : À la fin de ce chapitre, tu sauras créer des rôles Ansible propres, structurés et réutilisables d’un projet à l’autre. ⏱️ Durée estimée : 45 minutes | Niveau : Intermédiaire

Tu sais écrire des playbooks. Mais ton playbook de 400 lignes qui installe Nginx, configure le firewall et déploie ton app, personne n’a envie de le maintenir — toi inclus dans 6 mois. Les roles Ansible règlent ce problème : tu découpes ta logique en blocs indépendants, paramétrables et réutilisables. C’est le passage obligé pour faire de l’infra-as-code propre en équipe.

Pourquoi les roles changent tout

Sans roles, ton code Ansible ressemble à un script bash géant : ça marche, mais c’est fragile. Dès que tu ajoutes un deuxième projet ou un collègue, c’est le chaos.

Un role, c’est une fonction pour ton infra. Tu encapsules une responsabilité unique (installer Nginx, configurer un user, déployer une app), tu exposes des variables pour le paramétrage, et tu réutilises ce bloc partout. Plus de copier-coller entre projets.

🔥 Cas réel — Une équipe SRE que je connais maintenait 12 playbooks quasi identiques pour 12 microservices. Passage aux roles : un seul role deploy-app paramétré par variables, 12 fichiers de config de 10 lignes chacun. Temps de maintenance divisé par 5.

Les bénéfices concrets :

  • Lisibilité : un playbook principal de 20 lignes au lieu de 500
  • Réutilisation : le même role Nginx sur tes environnements dev, staging et prod
  • Testabilité : tu testes un role isolément avec Molecule
  • Collaboration : chaque role a son owner, son README, ses defaults documentés

Comprendre la structure d’un role

Ansible impose une convention de répertoires stricte. Pas de config à faire : si les dossiers existent au bon endroit, Ansible les trouve tout seul.

Voici l’arborescence type d’un role nginx :

roles/
└── nginx/
    ├── defaults/main.yml     # Variables par défaut (facilement surchargées)
    ├── vars/main.yml         # Variables internes (priorité haute)
    ├── tasks/main.yml        # Tâches à exécuter
    ├── handlers/main.yml     # Actions sur notify (restart, reload)
    ├── templates/            # Fichiers Jinja2 (.j2)
    ├── files/                # Fichiers statiques copiés tels quels
    ├── meta/main.yml         # Dépendances et métadonnées
    └── README.md

💡 Tip DevOpsdefaults/ vs vars/ : mets dans defaults/ tout ce que l’utilisateur du role peut vouloir changer (ports, chemins, feature flags). Réserve vars/ aux valeurs internes que personne ne devrait toucher. La différence est la priorité dans le système de précédence d’Ansible.

🧠 À retenir — Tu n’es pas obligé de créer tous les dossiers. Un role avec juste tasks/main.yml fonctionne. Ajoute les autres au fur et à mesure du besoin.

Commandes essentielles

Pour initialiser un role, ansible-galaxy te génère le squelette complet en une commande :

# Créer la structure d'un role
ansible-galaxy init roles/nginx

# Lister les roles installés
ansible-galaxy list

# Installer un role depuis Galaxy (le registry communautaire)
ansible-galaxy install geerlingguy.docker

⚠️ Attentionansible-galaxy init crée aussi des dossiers tests/ et des fichiers souvent inutiles. Supprime ce que tu n’utilises pas pour garder ton repo clean.

Pour utiliser un role dans un playbook, la syntaxe est directe :

---
- name: Configurer les serveurs web
  hosts: webservers
  become: true

  roles:
    - role: nginx
      vars:
        nginx_port: 8080
    - role: certbot

Tu peux aussi appeler un role dynamiquement dans une tâche avec include_role quand tu as besoin de logique conditionnelle :

- name: Installer le monitoring si activé
  ansible.builtin.include_role:
    name: monitoring
  when: monitoring_enabled | default(false)

Cas concret : role Nginx production-ready

Imaginons que tu dois déployer Nginx sur 30 serveurs avec des configs différentes par environnement. Voici comment structurer ça proprement.

Le fichier defaults/main.yml expose les paramètres que chaque équipe peut surcharger :

---
nginx_port: 80
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_server_tokens: "off"
nginx_client_max_body_size: "64m"
nginx_gzip: true
nginx_vhosts: []

Le fichier tasks/main.yml contient la logique d’installation et de configuration. Chaque tâche qui modifie la config notifie un handler pour recharger Nginx :

---
- name: Installer Nginx
  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: true
    cache_valid_time: 3600

- name: Déployer la configuration principale
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: nginx -t -c %s
  notify: Reload nginx

- name: Configurer les vhosts
  ansible.builtin.template:
    src: vhost.conf.j2
    dest: "/etc/nginx/sites-available/{{ item.server_name }}.conf"
  loop: "{{ nginx_vhosts }}"
  notify: Reload nginx

- name: Activer les vhosts
  ansible.builtin.file:
    src: "/etc/nginx/sites-available/{{ item.server_name }}.conf"
    dest: "/etc/nginx/sites-enabled/{{ item.server_name }}.conf"
    state: link
  loop: "{{ nginx_vhosts }}"

- name: Démarrer et activer Nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Et le fichier handlers/main.yml gère les redémarrages. Le handler ne se déclenche qu’une seule fois en fin de play, même si plusieurs tâches l’appellent :

---
- name: Reload nginx
  ansible.builtin.service:
    name: nginx
    state: reloaded

- name: Restart nginx
  ansible.builtin.service:
    name: nginx
    state: restarted

🔥 Cas réel — L’option validate: nginx -t -c %s dans la tâche template est un filet de sécurité crucial. Ansible vérifie la syntaxe de ta config avant de l’écrire. Sans ça, un template cassé = Nginx qui refuse de reload = downtime.

Pièges fréquents

1. Confondre defaults/ et vars/ Les variables dans vars/ écrasent presque tout, y compris ce que l’utilisateur passe dans son playbook. Si tu mets un port dans vars/main.yml, personne ne pourra le surcharger facilement. Règle simple : 90% de tes variables vont dans defaults/.

⚠️ Attention — L’ordre de précédence des variables Ansible a 22 niveaux. Retiens juste : defaults < variables de playbook < vars < extra-vars CLI. Le reste, consulte la doc quand tu as un doute.

2. Handlers qui ne se déclenchent pas Un handler ne s’exécute que si la tâche qui le notifie a effectivement changé quelque chose (status changed). Si ta config est déjà à jour, pas de notify, pas de reload. C’est voulu — mais ça surprend.

3. Roles trop gros Un role qui installe Nginx, configure le SSL, déploie ton app et met en place le monitoring fait trop de choses. Un role = une responsabilité. Découpe.

💡 Tip DevOps — Nomme tes roles avec un préfixe si tu en as beaucoup : infra-nginx, app-api, monitoring-prometheus. Ça aide à naviguer dans un roles/ avec 20+ entrées.

4. Oublier le README Un role sans documentation est un role que personne (y compris toi dans 3 mois) ne réutilisera. Liste les variables de defaults/, donne un exemple de playbook, mentionne les dépendances.

Exercice pratique

Crée un role app-deploy qui :

  1. Installe les dépendances système (paquet git et python3-pip)
  2. Clone un dépôt Git dans /opt/myapp (URL paramétrable via defaults/)
  3. Copie un fichier de config depuis un template Jinja2 avec les variables d’environnement
  4. Redémarre un service myapp via un handler quand la config change

Teste-le avec un playbook qui appelle ton role sur localhost :

---
- name: Déployer mon application
  hosts: localhost
  connection: local
  become: true

  roles:
    - role: app-deploy
      vars:
        app_repo: "https://github.com/ton-user/ton-app.git"
        app_env: production

🧠 À retenir — Les roles sont le building block fondamental d’une infra Ansible maintenable. Un role = une responsabilité, des defaults documentés, un README, et des handlers pour les side-effects. Commence simple, découpe quand ça grossit. Dans le prochain chapitre, on explore Ansible Galaxy pour tirer parti des roles communautaires et accélérer tes déploiements.

🖥️ Pratique sur ton propre serveur

Pour suivre Ansible en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés