
Par défaut, Ansible exécute chaque tâche sur 5 hôtes en parallèle, simultanément, et attend que tous finissent avant de passer à la tâche suivante. Ce comportement marche bien pour 5-20 hôtes, mais devient problématique sur grande échelle (paralléliser plus pour aller vite) ou en production sensible (serializer les hôtes pour faire un rolling update). Cette page couvre les 5 leviers de parallélisme d’Ansible : forks, serial, throttle, strategy, max_fail_percentage — et explique quand utiliser lequel.
C’est un terrain où la performance et la fiabilité entrent souvent en conflit. Bien tuner ces paramètres permet de descendre un déploiement de 30 minutes à 5 minutes sur 200 hôtes, ou de garantir un rolling update sans coupure sur 50 webservers.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »forks: combien de connexions SSH parallèles ouvre Ansible ;serial: traiter les hôtes par lots séquentiels (rolling update) ;throttle: limiter une tâche spécifique à N hôtes simultanés ;strategy: comment Ansible synchronise entre hôtes :linear,free,host_pinned,debug;max_fail_percentage: circuit breaker sur un déploiement.
forks — le nombre de connexions parallèles
Section intitulée « forks — le nombre de connexions parallèles »forks détermine combien de hôtes Ansible traite en parallèle pour chaque tâche. Configuration au choix :
# ansible.cfg[defaults]forks = 20# CLIansible-playbook site.yml -f 20# Variable d'environnementANSIBLE_FORKS=20 ansible-playbook site.ymlValeur par défaut : 5. Pour aller vite sur grande fleet, on monte à 20-50 :
| Taille de fleet | forks recommandé |
|---|---|
| < 20 hôtes | 5 (défaut, OK) |
| 20-100 hôtes | 20-30 |
| 100-500 hôtes | 50 |
| > 500 hôtes | 100+ (avec mitogen pour aller plus loin) |
serial — rolling updates
Section intitulée « serial — rolling updates »serial impose à Ansible de traiter les hôtes par lots séquentiels. Indispensable pour un rolling update qui ne doit pas tout casser d’un coup :
- name: Déployer nginx en rolling hosts: webservers serial: 1 # un hôte à la fois tasks: - name: ...Variantes :
serial: 1 # lot de 1 hôteserial: "20%" # lot = 20% du groupe (arrondi)serial: [1, 5, 20] # lot 1 : 1 hôte, lot 2 : 5, lots suivants : 20serial: - 1 # idem mais en YAML multiligne - "10%" - "100%"La stratégie de canary classique : [1, 10, 100]. Le premier lot teste sur 1 hôte (canary), le deuxième sur 10 (validation), puis 100% si tout va bien.
serial: + pre_tasks/post_tasks = rolling zero-downtime
Section intitulée « serial: + pre_tasks/post_tasks = rolling zero-downtime »Le pattern complet pour un rolling update sans coupure de service :
- name: Déployer en rolling hosts: webservers serial: 1 become: true
pre_tasks: - name: Drainer du load-balancer community.general.consul_kv: key: "lb/weight/{{ inventory_hostname }}" value: "0"
tasks: - name: Déployer la nouvelle version ansible.builtin.dnf: name: nginx state: latest
- name: Vérifier que nginx redémarre OK ansible.builtin.wait_for: port: 80 timeout: 30
post_tasks: - name: Réintégrer dans le LB community.general.consul_kv: key: "lb/weight/{{ inventory_hostname }}" value: "100"Sur 5 webservers, le déploiement prend 5x plus de temps mais aucun client ne voit de coupure.
throttle — limiter une tâche spécifique
Section intitulée « throttle — limiter une tâche spécifique »throttle: limite une tâche à N hôtes simultanés, sans toucher au reste du play :
tasks: - name: Tâche normale (parallélisée selon forks) ansible.builtin.dnf: name: nginx state: present
- name: Tâche qui martèle un service externe (limiter à 2 simultanés) ansible.builtin.uri: url: "https://api.externe.com/register/{{ inventory_hostname }}" method: POST throttle: 2
- name: Tâche normale (à nouveau parallélisée) ansible.builtin.systemd: name: nginx state: startedCas typique : une API externe avec rate limiting, une base de données avec écritures coûteuses, une registry Docker privée.
strategy — comment Ansible synchronise
Section intitulée « strategy — comment Ansible synchronise »Quatre stratégies disponibles :
strategy: linear (défaut)
Section intitulée « strategy: linear (défaut) »Tous les hôtes exécutent la même tâche en parallèle. Ansible attend que tous finissent avant de passer à la tâche suivante :
Tâche 1 : web1 → web2 → web3 (en parallèle, attend tous)Tâche 2 : web1 → web2 → web3 (en parallèle, attend tous)Tâche 3 : web1 → web2 → web3 (en parallèle, attend tous)Comportement prévisible : à chaque instant, tous les hôtes sont sur la même tâche. C’est ce que vous voulez 99% du temps.
strategy: free
Section intitulée « strategy: free »Chaque hôte avance à son rythme, sans synchro entre tâches :
- hosts: webservers strategy: free tasks: - name: Compiler une grosse lib (long) ansible.builtin.shell: make -j4Si web1 finit en 2 min et web2 en 5 min, web1 passe à la tâche 2 sans attendre web2. Gain de temps important quand les tâches sont longues et indépendantes (build, compilation, tests).
Inconvénient : la sortie devient désordonnée (output de tâches différentes intercalées) et le diagnostic plus complexe.
strategy: host_pinned
Section intitulée « strategy: host_pinned »Variante de free : chaque hôte est pinné à un worker dédié. Les hôtes avancent à leur rythme mais on garantit qu’un même hôte n’est pas pris par plusieurs workers concurrents. Cas marginal, à utiliser uniquement si vous avez un problème spécifique.
strategy: debug
Section intitulée « strategy: debug »Mode interactif : Ansible exécute une tâche à la fois et attend votre Enter avant de passer à la suivante :
ANSIBLE_STRATEGY=debug ansible-playbook site.ymlQuand une tâche échoue, vous tombez dans un mini-shell Ansible qui permet de :
- Réexécuter la tâche (
r) ; - Continuer au suivant (
c) ; - Quitter (
q) ; - Inspecter une variable (
p var_name).
Indispensable pour développer un playbook complexe en mode pas-à-pas.
max_fail_percentage — circuit breaker
Section intitulée « max_fail_percentage — circuit breaker »Sans max_fail_percentage:, le play continue tant qu’au moins un hôte réussit. Avec :
- name: Déployer hosts: webservers serial: 1 max_fail_percentage: 0 # arrêter dès la 1ère erreurmax_fail_percentage: 30 # arrêter si > 30% des hôtes ont échouéCombiné avec serial:, c’est le circuit breaker d’un déploiement : vous n’écrivez pas une bug sur l’ensemble de la fleet. Si web1 plante, web2 ne reçoit pas le déploiement.
Tuning combiné — exemple production
Section intitulée « Tuning combiné — exemple production »Un playbook prod typique sur 100 hôtes :
- name: Déploiement applicatif hosts: webservers # 100 hôtes serial: "10%" # lots de 10 hôtes max_fail_percentage: 5 # arrêter si > 5 hôtes du lot ont échoué strategy: linear # synchronisation par tâche
tasks: - name: Drainer du LB community.general.consul_kv: ...
- name: Déployer ansible.builtin.dnf: name: app state: latest
- name: API call qui rate-limite ansible.builtin.uri: url: ... throttle: 3 # max 3 calls API simultanésLancement avec forks adapté :
ansible-playbook site.yml -f 2010 hôtes en parallèle par lot, 10 lots, soit 100 hôtes traités. Avec max_fail_percentage: 5, si plus de 5 hôtes du lot courant échouent, le déploiement s’arrête net — on n’envoie pas la même erreur sur les 90 hôtes suivants.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
forks = 100 ralentit le poste | Saturation mémoire / FD côté control node | Réduire à 20-50 ou utiliser un Execution Environment dédié |
serial: ne change rien | Vous avez un seul hôte cible (ou --limit web1) | serial: ne s’applique qu’à un groupe avec plusieurs hôtes |
strategy: free rend les logs illisibles | C’est par design (hôtes désynchronisés) | Utiliser linear sauf gain de temps massif |
throttle: ignoré | throttle: 0 ou non défini = pas de limite | Vérifier la valeur, doit être ≥ 1 |
max_fail_percentage: 100 ne s’arrête jamais | 100% = jamais d’arrêt | Pour arrêter à la 1ère erreur : max_fail_percentage: 0 |
| Un play qui suit ne tourne pas après échec | C’est attendu : le play d’après ne démarre que si le précédent a au moins un hôte OK | Vérifier la convention multi-plays |
À retenir
Section intitulée « À retenir »forks(CLI-fouansible.cfg) contrôle le nombre de connexions SSH parallèles. Défaut 5, montez à 20-50 pour grande fleet.serial:réalise un rolling update par lots (1 hôte, 20%, ou patterns[1, 10, 100]).throttle:limite une tâche spécifique à N hôtes simultanés (API externe, DB, registry).strategy: linear(défaut) synchronise par tâche ;freedésynchronise pour aller plus vite ;debugactive le pas-à-pas interactif.max_fail_percentage:est le circuit breaker — combiné avecserial:, vous évitez de propager un bug à toute la fleet.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/parallelisme-strategies/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : rolling update avec serial:1 + max_fail_percentage:0 sur webservers (timestamps croissants).
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/parallelisme-strategies/
cat README.md # tuto pas à pascat challenge/README.md # consigne du challenge finalpytest -v challenge/tests/ # lancer les tests testinfraSi les tests passent, vous maîtrisez les concepts couverts dans ce guide. En
cas de blocage, docs/troubleshooting.md
à la racine du repo couvre les pièges fréquents (rate-limit SSH, clé absente,
collection manquante).