đ§ Ansible â Automatisation, Playbooks & DĂ©ploiement Django
Guide complet IDEOâLab : Agentless, Inventaire, Playbooks, Roles & Vault.
Vue d'ensemble
Automatisation (IaC), Push, Agentless (SSH).
IaC AgentlessArchitecture
Control Node -> (SSH) -> Managed Nodes.
Control Node Managed NodeInstallation (Control Node)
pip install ansible (reco), apt, dnf.
Setup Connexion (SSH)
Prérequis : ssh-keygen, ssh-copy-id.
Inventaire (Format INI)
inventory.ini, groupes, [all:vars].
Inventaire (Format YAML)
Syntaxe YAML, groupes imbriqués.
Inventory YAMLCommandes Ad-Hoc
ansible [hosts] -m [module] (ping, shell, apt).
Anatomie (Playbook)
YAML, hosts, become, tasks, Idempotence.
Modules Clés (SystÚme)
apt, dnf, systemd, user, file, copy.
Exemple : Playbook Django
git, pip (requirements.txt), command (migrate).
Variables (vars)
vars:, vars_files:, -e (extra-vars).
Boucles & Conditions
loop:, when:, ansible_facts.
Handlers (Notification)
notify:, handlers: (ex: restart nginx).
Templates (Jinja2)
template:, .j2, {{}}, {%%}.
Roles (Architecture)
ansible-galaxy init, tasks/, vars/, handlers/.
Ansible Vault (Secrets)
ansible-vault create, --ask-vault-pass.
Cheat-sheet
ansible, ansible-playbook, flags (-i, -l, --check).
Gestion de Configuration (IaC)
Ansible est un outil d'automatisation IT open-source (Red Hat) qui gÚre la **configuration des serveurs** (Configuration Management) et le **déploiement d'applications** (Application Deployment).
Il s'inscrit dans la philosophie **IaC (Infrastructure as Code)** : la configuration de vos serveurs (quoi installer, quels fichiers copier, quels services démarrer) est écrite dans des fichiers (YAML), versionnée dans Git, et reproductible.
ProblĂšme rĂ©solu : Ăviter le "Configuration Drift" (dĂ©rive de configuration), oĂč chaque serveur de production est lĂ©gĂšrement diffĂ©rent car configurĂ© Ă la main.
"Agentless" (Sans Agent)
C'est la caractéristique principale d'Ansible, qui le différencie de ses concurrents (Puppet, Chef).
ModĂšle "Agent" (ex: Puppet)
Vous devez installer un "Agent" (un service) sur *chaque* serveur. Cet agent contacte un "Master" (serveur central) pour "tirer" (Pull) sa configuration. Lourd Ă mettre en place.
ModĂšle "Agentless" (Ansible)
Il n'y a **rien Ă installer** sur les serveurs cibles (Managed Nodes).
Ansible fonctionne en mode **Push** :
- Il se connecte Ă vos serveurs via SSH (standard Linux).
- Il copie un petit module Python temporaire (en JSON).
- Il exécute le module (ex: `apt install nginx`).
- Il rĂ©cupĂšre le rĂ©sultat (OK/ChangĂ©/Ăchec).
- Il supprime le module.
Prérequis : Un accÚs SSH (port 22) et un interpréteur Python (déjà présent sur 99% des Linux).
Les 3 Composants Clés
- Control Node (NĆud de ContrĂŽle) : Votre machine (ex: votre PC ou un bastion) oĂč Ansible est **installĂ©**. C'est d'ici que vous lancez les commandes
ansible-playbook. - Managed Nodes (NĆuds GĂ©rĂ©s) : Vos serveurs cibles (Web, BDD...). Ils n'ont *rien* d'installĂ©, juste un accĂšs SSH.
- Inventory (Inventaire) : Un simple fichier (INI ou YAML) sur le Control Node qui liste les IPs/DNS des Managed Nodes et les organise en groupes (ex:
[webservers],[dbservers]).
Schéma de flux (SSH)
[Image d'une architecture Ansible]
+-----------------------+
| Control Node |
| (Votre PC / Bastion) |
| |
| - Ansible (Installé) |
| - Inventory (fichier) |
| - Playbook.yml |
+-----------------------+
|
| (ansible-playbook -i inventory playbook.yml)
|
| (Connexion SSH, Port 22)
|
+-----------------+-----------------+
| | |
⌠⌠âŒ
+-----------+ +-----------+ +-----------+
| Managed 1 | | Managed 2 | | Managed 3 |
| (Web 1) | | (Web 2) | | (DB 1) |
| (Python) | | (Python) | | (Python) |
+-----------+ +-----------+ +-----------+
Méthode pip (Python venv)
(Recommandé) Permet d'isoler Ansible et ses dépendances dans un environnement virtuel, et d'avoir la version la plus récente.
# 1. Créer un dossier pour votre config IaC mkdir ~/ansible_project && cd ~/ansible_project # 2. Créer un venv Python python3 -m venv .venv source .venv/bin/activate # 3. Installer Ansible (et 'ansible-lint' pour le debug) pip install ansible ansible-lint
Méthode "Paquet SystÚme" (Simple, mais souvent obsolÚte)
Ubuntu / Debian
sudo apt update sudo apt install -y ansible
RHEL / Rocky / AlmaLinux
# (Nécessite EPEL ou repo Ansible) sudo dnf install -y epel-release sudo dnf install -y ansible-core
ssh-copy-id)Ansible utilise SSH. Pour éviter de taper un mot de passe à *chaque* connexion, on utilise un échange de clés SSH.
1. (Sur le Control Node) Générer une clé
Si vous n'en avez pas déjà une (ls ~/.ssh/id_rsa.pub).
# (Appuyez 'Entrée' 3 fois pour accepter les défauts) ssh-keygen -t rsa -b 4096 # (Crée id_rsa (privée) et id_rsa.pub (publique))
2. (Sur le Control Node) Copier la clé vers les Cibles
ssh-copy-id copie votre clé publique (id_rsa.pub) dans ~/.ssh/authorized_keys du serveur distant.
# (à faire 1 fois pour chaque serveur) # (Utilisez l'utilisateur que vous utiliserez pour Ansible, ex: 'ideo_user') ssh-copy-id ideo_user@192.168.1.10 ssh-copy-id ideo_user@192.168.1.11 # 3. Vérifier (doit se connecter SANS mot de passe) ssh ideo_user@192.168.1.10
Créez un fichier inventory.ini (ou hosts.ini). C'est la liste de vos serveurs.
# inventory.ini
# --- Groupe [webservers] ---
[webservers]
web1.ideolab.com ansible_host=192.168.1.10
web2.ideolab.com ansible_host=192.168.1.11
# --- Groupe [dbservers] ---
[dbservers]
db1.ideolab.com ansible_host=192.168.1.12
# --- Groupe de groupes ('children') ---
[production:children]
webservers
dbservers
# --- Variables (s'appliquant Ă tous) ---
[all:vars]
# L'utilisateur SSH Ă utiliser (celui de ssh-copy-id)
ansible_user=ideo_user
# Utiliser sudo (devenir root)
ansible_become=truePlus moderne, permet des structures (groupes imbriqués) plus complexes.
# inventory.yml
all:
# Variables globales (s'applique Ă 'all')
vars:
ansible_user: ideo_user
ansible_become: true
children:
# Groupe 'production'
production:
children:
webservers:
hosts:
web1.ideolab.com:
ansible_host: 192.168.1.10
web2.ideolab.com:
ansible_host: 192.168.1.11
dbservers:
hosts:
db1.ideolab.com:
ansible_host: 192.168.1.12/usr/bin/ansible)ansible (sans -playbook) permet de lancer une seule tĂąche rapide sur un groupe de serveurs. Parfait pour le debug ou une action simple.
Syntaxe : ansible [hosts] -i [inventaire] -m [module] -a [args]
# (On suppose inventory.ini dans le dossier) # 1. Tester la connexion (Module 'ping') ansible all -m ping # 2. Exécuter une commande shell (Module 'shell') ansible webservers -m shell -a "uptime" # 3. Exécuter une commande (root) ansible webservers -m shell -a "hostname" --become # 4. Utiliser un module (Module 'apt') ansible webservers -m apt -a "name=nginx state=present" --become # 5. Redémarrer ansible webservers -m systemd -a "name=nginx state=restarted" --become
ansible-playbook)Le "Livre de Recettes"
Un Playbook (fichier .yml) est le cĆur d'Ansible. Il dĂ©crit un Ă©tat dĂ©sirĂ© (idempotent) pour un groupe d'hĂŽtes.
Idempotent : Si vous lancez le playbook 100 fois, le rĂ©sultat est le mĂȘme. S'il est dĂ©jĂ Ă l'Ă©tat dĂ©sirĂ©, Ansible ne fait rien (Statut: "OK"). S'il doit changer quelque chose, (Statut: "Changed").
deploy_nginx.yml (Anatomie)
---
# (Un Playbook est une liste de "Plays")
- name: Play 1 - Configurer les serveurs Web
# 1. Cible (Groupe de l'inventaire)
hosts: webservers
# 2. Devenir 'root' (sudo)
become: true
# 3. Liste des tĂąches
tasks:
- name: "TĂąche 1 - Installer Nginx (Debian)"
apt:
name: nginx
state: present
when: ansible_facts['os_family'] == "Debian"
- name: "TĂąche 2 - Installer Nginx (RHEL)"
dnf:
name: nginx
state: present
when: ansible_facts['os_family'] == "RedHat"
- name: "Tùche 3 - Démarrer le service"
systemd:
name: nginx
state: started
enabled: trueGestion de paquets (Idempotent)
- name: Installer les paquets de base
apt:
name: ['nginx', 'ufw', 'fail2ban']
state: present
update_cache: yes
- name: Supprimer un paquet
apt:
name: apache2
state: absentGestion de Fichiers
- name: Créer un dossier web
file:
path: /var/www/mon_site
state: directory
owner: www-data
mode: '0755'
- name: Copier un fichier local vers le serveur
copy:
src: ./files/mon_index.html
dest: /var/www/mon_site/index.html
owner: www-data
- name: Gérer une ligne dans un fichier
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
state: presentGestion de Services (systemd)
- name: S'assurer que Nginx est démarré et activé
systemd:
name: nginx
state: started
enabled: true
daemon_reload: yes
- name: Recharger Nginx
systemd:
name: nginx
state: reloaded---
- name: Déployer l'application Django
hosts: webservers
become: true
vars:
project_path: /opt/ideo-lab/mon_projet
repo_url: https://github.com/ideo-lab/mon_projet.git
tasks:
- name: "1. Installer les paquets systĂšme (Python, Git, Nginx...)"
apt:
name: ['python3-venv', 'python3-pip', 'git', 'nginx']
state: present
- name: "2. Cloner le dépÎt (Source)"
git:
repo: "{{ repo_url }}"
dest: "{{ project_path }}"
version: main # (Branche)
force: yes
- name: "3. Installer les dépendances Python (requirements.txt)"
pip:
requirements: "{{ project_path }}/requirements.txt"
virtualenv: "{{ project_path }}/.venv"
- name: "4. Lancer les migrations (via 'command')"
command:
cmd: "python manage.py migrate"
chdir: "{{ project_path }}"
environment:
# (Charge les variables .env si besoin)
DJANGO_SETTINGS_MODULE: "mon_projet.settings"
- name: "5. Lancer collectstatic"
command:
cmd: "python manage.py collectstatic --noinput"
chdir: "{{ project_path }}"
- name: "6. (Voir 4.1) Redémarrer Gunicorn (via Handler)"
systemd:
name: gunicorn
state: restarted
vars)Variables dans le Playbook
---
- hosts: webservers
# 1. Variables du Play
vars:
http_port: 8080
project_path: /var/www/mon_app
tasks:
- name: Créer le dossier
file:
path: "{{ project_path }}"
state: directory
- name: Installer paquet
apt:
name: "{{ 'nginx' if http_port == 80 else 'apache2' }}"
Variables dans un Fichier (vars_files)
Déplacer les variables hors du Playbook (bonne pratique).
# vars/config.yml http_port: 8080 project_path: /var/www/mon_app
# playbook.yml
---
- hosts: webservers
vars_files:
- vars/config.yml
tasks:
- name: Créer le dossier
file:
path: "{{ project_path }}"
state: directoryVariables Externes (-e) (Priorité Max)
Passer des variables depuis la ligne de commande. Surcharge tout le reste.
ansible-playbook deploy.yml -e "http_port=9000" # (Peut aussi charger un fichier) ansible-playbook deploy.yml -e "@vars/prod_secrets.yml"
Concept
ProblÚme : Vous modifiez 10 fichiers de config Nginx. Vous ne voulez pas recharger Nginx 10 fois (lent), mais 1 seule fois, à la fin, et *seulement* si un fichier a changé.
Solution : Un "Handler" (gestionnaire) est une tùche qui n'est exécutée que si elle est "notifiée" par une autre tùche (qui a eu le statut "changed").
Exemple (Reload Nginx)
---
- hosts: webservers
become: true
tasks:
- name: "Copier la config Nginx"
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
# 1. Notifier le handler
notify: Reload Nginx
- name: "Copier le VHost Django"
copy:
src: files/django.conf
dest: /etc/nginx/sites-available/django
# 2. Notifier le MĂME handler
notify: Reload Nginx
# 3. Définir le Handler (à la fin du play)
handlers:
- name: Reload Nginx
systemd:
name: nginx
state: reloadedGénérer des fichiers de config
copy: est statique. Le module template: utilise le moteur **Jinja2** (le mĂȘme que Django !) pour copier un fichier en remplaçant les variables.
# playbook.yml
---
- hosts: webservers
become: true
vars:
server_domain: "ideolab.com"
app_socket: "/run/gunicorn.sock"
tasks:
- name: "Générer et copier le VHost Nginx"
template:
src: templates/nginx.conf.j2
dest: "/etc/nginx/sites-available/{{ server_domain }}"
notify: Reload Nginx
handlers:
- name: Reload Nginx
systemd: { name: nginx, state: reloaded }templates/nginx.conf.j2 (Template Jinja2)
(Note : La syntaxe {{ ... }} est pour échapper Django, pas pour Ansible).
server {
listen 80;
# Utilise la variable du 'vars:'
server_name {{ server_domain }};
location /static/ {
alias /var/www/{{ server_domain }}/static/;
}
location / {
proxy_pass http://unix:{{ app_socket }};
include proxy_params;
}
# Boucle (Jinja2)
{% for user in ['admin', 'dev'] %}
# (Exemple de directive)
# allow 192.168.0.{{ loop.index }};
{% endfor %}
}Factoriser (DRY)
Les Playbooks deviennent illisibles. Un **Role** est une structure de dossiers standardisée pour regrouper des tùches (tasks), des variables (vars), des handlers, et des templates.
Initialiser un Role (ansible-galaxy)
ansible-galaxy init roles/nginx # (Crée l'arborescence)
Structure (roles/nginx/)
roles/nginx/
âââ tasks/
â âââ main.yml (TĂąches: apt, copy, systemd)
âââ handlers/
â âââ main.yml (Handler: "Reload Nginx")
âââ templates/
â âââ nginx.conf.j2
âââ vars/
â âââ main.yml (Variables par dĂ©faut)
âââ defaults/
âââ main.ymlUtiliser le Role (Playbook principal)
Le playbook devient une simple "liste de courses".
# deploy_stack.yml
---
- name: Configurer les serveurs Web
hosts: webservers
become: true
# 1. Appliquer les RĂŽles
roles:
- common # (Installe vim, git, fail2ban...)
- nginx # (Installe et configure Nginx via le template)
- django # (Installe Gunicorn, code, .env)
- name: Configurer les serveurs BDD
hosts: dbservers
become: true
roles:
- common
- postgresqlStocker les Secrets
â ïž Ne **jamais** commiter (git) de mots de passe (BDD, API) en clair dans vars/main.yml.
Ansible Vault est un outil (inclus) pour chiffrer (AES-256) des fichiers YAML contenant des secrets.
Commandes ansible-vault
# 1. CrĂ©er un fichier de secrets chiffrĂ© ansible-vault create vars/secrets.yml # (Demande un mot de passe) # 2. Ăditer le fichier ansible-vault edit vars/secrets.yml # 3. Lancer le playbook (en demandant le mot de passe) ansible-playbook deploy.yml --ask-vault-pass # (Utiliser un fichier de mdp) ansible-playbook deploy.yml --vault-password-file .vault_pass
Contenu de vars/secrets.yml (chiffré)
$ANSIBLE_VAULT;1.1;AES256 386634... (Données chiffrées)
Contenu (déchiffré)
db_password: "mon_pass_db" api_key: "sk_live_..."
Commandes Ad-Hoc (ansible)
# ( -i = inventaire, -m = module, -a = args, -b = become/sudo) # Ping (vérifie la connexion) ansible all -i inventory.ini -m ping # Commande Shell ansible webservers -i inv -m shell -a "df -h" # Utiliser un module (ex: reboot) ansible all -i inv -m reboot -b
Playbooks (ansible-playbook)
# Lancer un playbook ansible-playbook -i inventory.ini deploy.yml # Limiter Ă un groupe (ex: web) ansible-playbook -i inv deploy.yml -l webservers # Limiter Ă un host ansible-playbook -i inv deploy.yml -l web1.ideolab.com # (Dry Run) Voir ce qui *changerait* (ne fait rien) ansible-playbook -i inv deploy.yml --check # Voir les changements (diff) ansible-playbook -i inv deploy.yml --diff # Demander le mot de passe Vault ansible-playbook -i inv deploy.yml --ask-vault-pass
