Industrialiser Ansible : Roles & Vault
Faire passer votre automatisation à l'échelle avec une structure et une sécurité appropriées.
Roles (La Structure)
Ne mettez pas tout dans un seul fichier
Un playbook de 500 lignes est impossible à maintenir. Les roles fournissent une organisation modulaire et réutilisable.
Créer un Role
# Générer la structure standard d'un role
ansible-galaxy init my_role
# Ou avec un chemin personnalisé
ansible-galaxy init roles/nginx
Structure de Répertoire d'un Role
roles/
âââ nginx/
âââ defaults/
â âââ main.yml # Variables par dĂ©faut (prioritĂ© la plus basse)
âââ files/
â âââ nginx.conf # Fichiers statiques Ă copier
âââ handlers/
â âââ main.yml # Handlers (restart, reload)
âââ meta/
â âââ main.yml # MĂ©tadonnĂ©es du role, dĂ©pendances
âââ tasks/
â âââ main.yml # Liste principale des tasks (point d'entrĂ©e)
âââ templates/
â âââ site.conf.j2 # Templates Jinja2
âââ vars/
â âââ main.yml # Variables du role (prioritĂ© haute)
âââ README.md
| Répertoire | Objectif |
|---|---|
tasks/ |
Logique principale (requis) |
handlers/ |
Actions déclenchées (redémarrer les services) |
templates/ |
Fichiers Jinja2 (.j2) |
files/ |
Fichiers statiques Ă copier |
vars/ |
Variables du role (priorité haute) |
defaults/ |
Valeurs par défaut (priorité basse, surchargeable) |
meta/ |
Dépendances, métadonnées |
Utiliser les Roles
# site.yml
---
- name: Configure webservers
hosts: webservers
become: yes
roles:
- common # roles/common/
- nginx # roles/nginx/
- { role: app, app_port: 8080 } # Avec des variables
Role avec Tags et Conditions
roles:
- role: nginx
tags: webserver
when: "'webservers' in group_names"
- role: postgresql
tags: database
vars:
pg_version: 15
Exemple de Role : nginx
roles/nginx/tasks/main.yml :
---
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
tags: install
- name: Deploy configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Reload nginx
tags: config
- name: Ensure nginx is running
service:
name: nginx
state: started
enabled: yes
roles/nginx/handlers/main.yml :
---
- name: Reload nginx
service:
name: nginx
state: reloaded
- name: Restart nginx
service:
name: nginx
state: restarted
roles/nginx/defaults/main.yml :
Templates Jinja2 (Flexibilité)
Générer des fichiers de configuration dynamiques avec variables, boucles et conditions.
Syntaxe de Base
| Syntaxe | Objectif | Exemple |
|---|---|---|
{{ var }} |
Afficher une variable | {{ nginx_port }} |
{% ... %} |
Logique (if, for) | {% if enabled %} |
{# ... #} |
Commentaire | {# Ceci est ignoré #} |
{{ var \| filter }} |
Appliquer un filtre | {{ name \| upper }} |
Variables
# Variable basique
server_name {{ ansible_hostname }};
listen {{ nginx_port | default(80) }};
# AccÚs aux données imbriquées
{{ user.name }}
{{ servers[0].ip }}
# Facts
{{ ansible_default_ipv4.address }}
{{ ansible_memtotal_mb }}
Conditions
{% if env == 'production' %}
worker_processes {{ ansible_processor_vcpus }};
{% else %}
worker_processes 1;
{% endif %}
{# Condition inline #}
debug = {{ 'true' if debug_mode else 'false' }}
{# Vérifier si une variable est définie #}
{% if custom_config is defined %}
include {{ custom_config }};
{% endif %}
Boucles
# Boucle simple
{% for server in upstream_servers %}
server {{ server }};
{% endfor %}
# Boucle avec index
{% for user in users %}
# User {{ loop.index }}: {{ user.name }}
{% endfor %}
# Boucle avec condition
{% for vhost in vhosts if vhost.enabled %}
include /etc/nginx/sites-enabled/{{ vhost.name }}.conf;
{% endfor %}
# Boucle sur un dictionnaire
{% for key, value in settings.items() %}
{{ key }} = {{ value }};
{% endfor %}
Filtres
# Manipulation de chaĂźnes
{{ name | lower }}
{{ name | upper }}
{{ name | capitalize }}
{{ path | basename }}
{{ path | dirname }}
# Valeurs par défaut
{{ port | default(8080) }}
{{ config | default('none', true) }} # Aussi pour les chaĂźnes vides
# Listes
{{ servers | join(', ') }}
{{ items | length }}
{{ items | first }}
{{ items | last }}
{{ items | unique }}
{{ items | sort }}
# JSON/YAML
{{ data | to_json }}
{{ data | to_yaml }}
{{ data | to_nice_json(indent=2) }}
# Mathématiques
{{ value | int }}
{{ price | float }}
{{ values | sum }}
{{ values | max }}
Exemple de Template Complet
templates/nginx.conf.j2 :
# {{ ansible_managed }}
# Généré le {{ ansible_date_time.iso8601 }}
user www-data;
worker_processes {{ nginx_worker_processes | default('auto') }};
pid /run/nginx.pid;
events {
worker_connections {{ nginx_worker_connections | default(1024) }};
}
http {
sendfile on;
tcp_nopush on;
{% if nginx_gzip_enabled | default(true) %}
gzip on;
gzip_types text/plain text/css application/json;
{% endif %}
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.port | default(80) }};
server_name {{ vhost.server_name }};
root {{ vhost.root }};
{% if vhost.ssl | default(false) %}
ssl_certificate {{ vhost.ssl_cert }};
ssl_certificate_key {{ vhost.ssl_key }};
{% endif %}
}
{% endfor %}
}
Ansible Vault (Sécurité)
NE commitez JAMAIS de mots de passe en clair dans Git
Utilisez Ansible Vault pour chiffrer les données sensibles : mots de passe, clés API, certificats.
Créer un Fichier Chiffré
# Créer un nouveau fichier chiffré
ansible-vault create secrets.yml
# Chiffrer un fichier existant
ansible-vault encrypt secrets.yml
# Déchiffrer un fichier
ansible-vault decrypt secrets.yml
Ăditer & Visualiser
# Ăditer un fichier chiffrĂ© (dĂ©chiffre en mĂ©moire)
ansible-vault edit secrets.yml
# Voir le contenu sans éditer
ansible-vault view secrets.yml
# Changer le mot de passe
ansible-vault rekey secrets.yml
Structure du Fichier Chiffré
# secrets.yml (avant chiffrement)
---
db_password: SuperSecret123!
api_key: sk-1234567890abcdef
ssl_private_key: |
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQE...
-----END PRIVATE KEY-----
AprĂšs chiffrement, le fichier contient :
Exécution avec Vault
# Demander le mot de passe
ansible-playbook site.yml --ask-vault-pass
# Mot de passe depuis un fichier
ansible-playbook site.yml --vault-password-file ~/.vault_pass
# Plusieurs mots de passe vault
ansible-playbook site.yml --vault-id dev@~/.vault_dev --vault-id prod@~/.vault_prod
Utiliser les Variables Chiffrées
# playbook.yml
---
- hosts: databases
become: yes
vars_files:
- vars/main.yml
- vars/secrets.yml # Fichier chiffré
tasks:
- name: Configure database
template:
src: db.conf.j2
dest: /etc/myapp/db.conf
vars:
password: "{{ db_password }}" # Depuis secrets.yml
Chiffrer une Variable Unique
# Chiffrer une chaĂźne
ansible-vault encrypt_string 'SuperSecret123!' --name 'db_password'
# Sortie (Ă coller dans le fichier vars) :
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
6138653033326...
Bonnes Pratiques
Structure de Projet
ansible-project/
âââ ansible.cfg # Config locale
âââ inventory/
â âââ production/
â â âââ hosts # Serveurs de production
â â âââ group_vars/
â â âââ all.yml
â âââ staging/
â âââ hosts
â âââ group_vars/
â âââ all.yml
âââ group_vars/
â âââ all.yml # Variables pour tous les hĂŽtes
â âââ webservers.yml
â âââ databases.yml
âââ host_vars/
â âââ special-server.yml
âââ roles/
â âââ common/
â âââ nginx/
â âââ postgresql/
â âââ app/
âââ playbooks/
â âââ site.yml # Playbook maĂźtre
â âââ webservers.yml
â âââ databases.yml
âââ files/ # Fichiers statiques globaux
âââ templates/ # Templates globaux
âââ requirements.yml # DĂ©pendances de roles
ansible.cfg Optimisé
[defaults]
inventory = ./inventory/production
roles_path = ./roles
remote_user = deploy
private_key_file = ~/.ssh/ansible_key
# Performance
forks = 10 # HÎtes parallÚles (défaut : 5)
gathering = smart # Mettre en cache les facts
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400 # 24 heures
# Sortie
stdout_callback = yaml # Sortie lisible
display_skipped_hosts = False
# Sécurité
host_key_checking = False # Pour l'automation (moins sécurisé)
vault_password_file = ~/.vault_pass
[ssh_connection]
pipelining = True # Exécution plus rapide
control_path = /tmp/ansible-%%h-%%r
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = False
Astuces de Performance
| ParamĂštre | Impact |
|---|---|
forks = 10 |
Exécuter sur 10 hÎtes en parallÚle |
pipelining = True |
Réduire les opérations SSH |
gathering = smart |
Ne pas re-collecter les facts |
strategy: free |
Ne pas attendre l'hĂŽte le plus lent |
# Dans le playbook pour les tasks asynchrones
- name: Long running task
command: /usr/bin/long_task
async: 3600 # Durée max d'exécution
poll: 0 # Fire and forget
register: task_result
- name: Check task status
async_status:
jid: "{{ task_result.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 60
delay: 10
Référence Rapide
# Roles
ansible-galaxy init roles/myrole
ansible-galaxy install -r requirements.yml
# Vault
ansible-vault create secrets.yml
ansible-vault edit secrets.yml
ansible-vault encrypt_string 'secret' --name 'var_name'
ansible-playbook site.yml --ask-vault-pass
# Exécuter avec options
ansible-playbook site.yml -i inventory/prod --limit webservers
ansible-playbook site.yml --tags "config,deploy" --skip-tags "debug"
ansible-playbook site.yml --check --diff