Ansible - Les taches asynchrones
Publié le : 3 novembre 2021 | Mis à jour le : 22 janvier 2023Par défaut, Ansible lance les tâches de manière synchrone, en maintenant la connexion au nœud distant ouverte jusqu’à ce que l’action soit terminée. Cela signifie que dans un playbook, chaque tâche bloque la tâche suivante par défaut, ce qui signifie que les tâches suivantes ne s’exécuteront pas tant que la tâche en cours ne sera pas terminée.
Ce comportement peut poser des problèmes. Par exemple, une tâche peut prendre plus de temps que ne le permet les paramètres de la session SSH, provoquant un délai d’attente.
Vous souhaiteriez aussi qu’une tache de longue durée s’exécute en arrière-plan pendant que vous lancez d’autres tâches. C’est dans ces cas que le mode asynchrone va vous permettre de gérer l’exécution des tâches de longue durée.
Lancer des taches unitaires de manière asynchrone
Vous pouvez exécuter des opérations de longue durée en arrière-plan avec la
commande ansible
. Comme par exemple :
- Téléchargement d’un gros fichier à partir d’une URL
- Exécution d’un script connu pour s’exécuter pendant une longue durée
- Redémarrage du serveur distant et attendre son retour à la vie
Il suffit d’ajouter les paramètres -B timeout
définissant le temps maxi
d’exécution de la tache et -P val
.
Prenons l’exemple d’une mise à jour des packages d’une centos 8:
ansible all -B 3600 -P 0 -a -b "dnf -y update"
builder | CHANGED => {
"ansible_job_id": "77959305201.6882",
"changed": true,
"finished": 0,
"results_file": "/home/vagrant/.ansible_async/77959305201.6882",
"started": 1
}
Vous remarquez qu’à la sortie nous obtenons un job id que nous pouvons utiliser par la suite pour connaître le status d’une tache avec le module async_status.
ansible all -b -m async_status -a 'jid=562302021282.7210'
builder | SUCCESS => {
"ansible_job_id": "562302021282.7210",
"changed": false,
"finished": 0,
"started": 1
}
Si vous avez lancé la tache en changeant d’utilisateur,
par exemple avec un become:true -b
, il faudra bien demander le status avec le
même utilisateur!
Lancer des taches asynchrone dans vos playbooks
Ce mécanisme d’asynchronisme existe également pour les playbooks. Ici le
comportement du mode asynchrone sera fonction de la valeur poll
. Un exemple :
---
- hosts: all
become: true
tasks:
- name: Simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
ansible.builtin.command: /bin/sleep 15
async: 45
poll: 5
Lançons ce playbook :
PLAY [all] *****
TASK [Gathering Facts] *******
ok: [builder]
TASK [Simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec] ****
ASYNC POLL on builder: jid=254432505432.51116 started=1 finished=0
ASYNC POLL on builder: jid=254432505432.51116 started=1 finished=0
changed: [builder]
PLAY RECAP *****
builder : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Vous remarquez les interrogations au status du job lancé en arrière plan?
Si vous souhaitez lancer des taches en parallèle il suffit de passer 0 au
paramètre poll
.
Dans ce cas Ansible ne nettoiera pas le cache de travail il faudra alors utiliser
le module async_status
en lui passant l’option mode: cleanup
---
- hosts: all
become: true
tasks:
- name: Run an async task
ansible.builtin.yum:
name: docker-io
state: present
async: 1000
poll: 0
register: yum_sleeper
- name: Check on an async task
async_status:
jid: "{{ yum_sleeper.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 100
delay: 10
On peut également utiliser un compteur d’essai retries
qui arrivé à 0 fera
échouer la tache. Ici on checke le status de la tache pour la terminer si ell
passe à finished
en l’enregistrant dans la variable job_result
.
Une autre solution, utiliser le module wait_for
:
---
- name: Update server an reboot
hosts: all
tasks:
- name: Update
become: yes
become_user: root
tags: Patch
shell: "yum -y update"
register: patchresult
- name: Reboot the server
tags: reboot
become: yes
become_user: root
shell: "sleep 5 && reboot"
async: 1
poll: 0
- name: Wait for the reboot and reconnect
wait_for:
port: 22
host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
search_regex: OpenSSH
delay: 10
timeout: 60
connection: local
Pour lancer des taches asynchrones encore plus rapidement sur de nombreux
serveurs il faudra jouer avec le paramètre --forks
ou dans la configuration
d’ansible.
Je rappelle que ce billet n’est pas le seul mais un d’une longue série …