
La délégation Ansible permet d’exécuter une tâche sur un autre hôte que celui ciblé par le play, ou de ne l’exécuter qu’une seule fois quel que soit le nombre d’hôtes. Cas typique : pendant un déploiement sur 50 webservers, vous devez drainer chaque hôte du load-balancer (commande à lancer sur le LB, pas sur le webserver). C’est l’usage exact de delegate_to. De même, une migration de base de données ne doit tourner qu’une fois même si 5 webservers la déclenchent — c’est run_once.
Cette page couvre les trois mécanismes de délégation : delegate_to (rediriger vers un autre hôte), run_once (exécuter une seule fois), local_action (raccourci pour cibler le control node), avec les cas concrets de production où vous en aurez besoin.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »delegate_to: exécuter une tâche sur un hôte différent duhosts:du play ;run_once: forcer l’exécution sur un seul hôte quel que soit le nombre cible ;local_action: raccourci pourdelegate_to: localhost;delegate_facts: true: faire en sorte que les facts récupérés s’appliquent à l’hôte délégué ;- Les patterns de production : drain LB, migration DB one-shot, écriture inventaire dynamique.
delegate_to — exécuter ailleurs
Section intitulée « delegate_to — exécuter ailleurs »Une tâche dans un play hosts: webservers s’exécute sur chaque webserver. Avec delegate_to, vous redirigez l’exécution :
- name: Drainer du load-balancer hosts: webservers serial: 1 tasks: - name: Marquer {{ inventory_hostname }} comme drain dans HAProxy ansible.builtin.shell: | echo "disable server backend/{{ inventory_hostname }}" \ | socat stdio /var/run/haproxy.sock delegate_to: lb1.lab # ← exécution SUR lb1, mais en boucle pour chaque webserverLe play boucle sur chaque webserver mais chaque itération exécute la commande sur lb1.lab, en injectant {{ inventory_hostname }} (le webserver courant) dans la commande. Résultat : le LB drainera web1, puis web2, puis web3 successivement.
delegate_to accepte un hôte de l’inventaire (lb1.lab), un groupe (avec groups['lbs'][0]), ou une adresse IP littérale.
run_once — une seule exécution
Section intitulée « run_once — une seule exécution »Une tâche en run_once: true ne s’exécute que sur le premier hôte du play, peu importe combien d’hôtes sont ciblés :
- name: Migration de base hosts: webservers tasks: - name: Lancer la migration SQL (UNE SEULE FOIS) ansible.builtin.command: /usr/local/bin/migrate.sh run_once: true delegate_to: db1.lab # ← combiné : 1 fois, sur db1run_once seul exécute la tâche sur un webserver au hasard (le premier de la liste). Combiné à delegate_to: db1.lab, la tâche tourne une seule fois sur db1. C’est le pattern migration one-shot.
local_action — raccourci pour le control node
Section intitulée « local_action — raccourci pour le control node »local_action est un alias pour delegate_to: localhost :
- name: Récupérer un certificat depuis l'API locale ansible.builtin.uri: url: https://ca.local/issue delegate_to: localhost # version explicite
- name: Idem (forme courte) ansible.builtin.uri: url: https://ca.local/issue local_action: ansible.builtin.uri url=https://ca.local/issue # version raccourcieLa forme delegate_to: localhost est préférée car plus lisible (la forme courte local_action: mélange syntaxes).
Cas typique : interroger une API qui n’est joignable que depuis votre poste, générer un fichier qui sera ensuite distribué via copy:.
delegate_facts — où vont les facts
Section intitulée « delegate_facts — où vont les facts »Quand vous faites gather_facts: ou exécutez un module qui retourne des facts (setup, command avec register:), ces facts sont rattachés à l’hôte courant par défaut. Avec delegate_facts: true, ils sont rattachés à l’hôte délégué :
- name: Récupérer la config depuis lb1 ansible.builtin.command: cat /etc/haproxy/haproxy.cfg delegate_to: lb1.lab delegate_facts: true # le résultat va dans hostvars['lb1.lab'] register: lb_configSans delegate_facts: true, le résultat va dans hostvars['<hôte courant>'], ce qui est rarement ce que vous voulez quand la donnée concerne lb1.
Patterns de production
Section intitulée « Patterns de production »Drain de load-balancer (rolling deploy)
Section intitulée « Drain de load-balancer (rolling deploy) »Le pattern complet pour un rolling deploy avec drain :
- name: Déployer en rolling avec drain HAProxy hosts: webservers serial: 1 become: true
pre_tasks: - name: Drainer {{ inventory_hostname }} de HAProxy ansible.builtin.shell: | echo "disable server backend/{{ inventory_hostname }}" \ | socat stdio /var/run/haproxy.sock delegate_to: lb1.lab
- name: Attendre la fin des connexions actives ansible.builtin.wait_for: timeout: 30
tasks: - name: Déployer la nouvelle version ansible.builtin.dnf: name: app state: latest
post_tasks: - name: Réintégrer {{ inventory_hostname }} dans HAProxy ansible.builtin.shell: | echo "enable server backend/{{ inventory_hostname }}" \ | socat stdio /var/run/haproxy.sock delegate_to: lb1.labserial: 1 + delegate_to: lb1.lab = un webserver à la fois est drainé, déployé, réintégré.
Migration de schéma DB one-shot
Section intitulée « Migration de schéma DB one-shot »Plusieurs webservers démarrent l’application — la migration de schéma DB ne doit tourner qu’une fois :
- name: Déploiement applicatif hosts: webservers tasks: - name: Lancer la migration de schéma ansible.builtin.command: /opt/app/bin/migrate run_once: true delegate_to: db1.lab # une fois, sur la DB register: migration_result
- name: Démarrer l'application sur chaque webserver ansible.builtin.systemd: name: app state: started when: migration_result is definedInventaire dynamique mis à jour à la volée
Section intitulée « Inventaire dynamique mis à jour à la volée »Après création d’une VM, vous voulez l’ajouter à l’inventaire en mémoire pour le reste du playbook :
- name: Provisionner et configurer une nouvelle VM hosts: localhost tasks: - name: Créer la VM community.libvirt.virt: name: web3 state: running
- name: Ajouter web3 à l'inventaire en mémoire ansible.builtin.add_host: name: web3.lab groups: webservers ansible_host: 10.10.20.23
- name: Configurer la nouvelle VM hosts: web3.lab tasks: - name: Installer nginx ansible.builtin.dnf: name: nginxLe second play utilise l’hôte créé dynamiquement par le premier — sans avoir à réécrire l’inventaire fichier.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
delegate_to suivi mais facts ne s’appliquent pas | Manque delegate_facts: true | Ajouter delegate_facts: true si le but est de récupérer des facts pour l’hôte délégué |
run_once exécute sur le mauvais hôte | Sans delegate_to, run_once prend le premier de la liste (peut varier) | Toujours combiner run_once: true + delegate_to: <hôte> |
delegate_to: localhost mais SSH essaie de se connecter | connection: local n’est pas implicite | Ajouter connection: local ou utiliser local_action |
Variable inventory_hostname montre localhost au lieu du webserver | Vous lisez sur la tâche déléguée — inventory_hostname est l’hôte d’origine, pas la cible déléguée | Utiliser delegate_to_host (la cible) si besoin |
delegate_to: sur un hôte hors inventaire | Ansible ne sait pas comment se connecter | Ajouter via add_host: ou définir l’hôte dans l’inventaire |
À retenir
Section intitulée « À retenir »delegate_to: <hôte>redirige l’exécution d’une tâche vers un autre hôte — pattern drain LB.run_once: trueforce l’exécution sur un seul hôte (le premier) — combiner avecdelegate_to:pour fixer la cible.local_action:est l’alias dedelegate_to: localhost(préférer la forme explicite).delegate_facts: truerattache les facts à l’hôte délégué (utile pour lesregister:sur un hôte tiers).add_host:ajoute un hôte à l’inventaire en mémoire pour le reste du playbook (utile après provisioning dynamique).
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/delegation/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : delegate_to: db1.lab + run_once depuis un play webservers (1 seul fichier sur db1).
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/delegation/
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).