默认情况下,Ansible 同步运行任务:远程连接会一直保持到操作结束,剧本中的当前任务会阻塞下一任务。因此,耗时超过 SSH 会话允许时间的任务可能超时。有时也希望长操作在后台运行,同时继续其他任务。异步模式可以控制这些长任务的执行方式。
临时命令中的异步任务
使用临时命令,可以在后台执行长操作。下面以 long_running_operation 为例:-B 将最长运行时间设为 3600 秒,-P 0 表示不轮询。
$ ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"
稍后可以使用 async_status,传入启动时返回的任务 ID,查询状态:
$ ansible web1.example.com -m async_status -a "jid=488359678239.2844"
Ansible 也可以自动轮询长任务。大多数情况下,它会在轮询之间保持远程连接。下面允许任务运行 30 分钟,每 60 秒检查一次:
$ ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
轮询模式会先在全部目标机器上启动任务,再开始轮询。若希望快速启动所有任务,需要足够大的 --forks 值。超过 -B 指定的秒数后,远程节点上的进程会被终止。
异步模式较适合长时间运行的 Shell 命令或软件升级。让 copy 模块异步运行,并不意味着文件传输会变成后台传输。
剧本中的异步任务
剧本也支持异步模式与轮询,语法更简单。它可以避免连接超时,或者避免阻塞后续任务;具体行为取决于 poll 的值。
等待结果:poll 大于 0
若某个任务需要更长的超时限额,设置 async 并给 poll 一个正数。Ansible 仍会阻塞剧本的下一任务,直到异步任务完成、失败或超时;超时边界由 async 决定。
下面明确指定最长运行时间和轮询间隔:
---
- hosts: all
remote_user: root
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
默认轮询间隔由 DEFAULT_POLL_INTERVAL 决定。async 没有默认运行时限;省略该关键字时,任务按默认方式同步运行。
原文说明,自 Ansible 2.3 起,异步任务不支持检查模式,在检查模式下会失败。可以参考 检查模式与差异模式,了解如何跳过相关任务。
开启轮询的异步任务完成后,会自动删除临时任务缓存文件,其默认位置为 ~/.ansible_async/。
后台启动:poll 等于 0
若需要并发启动多个剧本任务,设置 async 和 poll: 0。Ansible 启动任务后立即继续下一任务,不等待结果。各异步任务会持续到完成、失败或运行时间超过 async 限制;剧本可以在没有再次检查这些任务的情况下结束。
---
- hosts: all
remote_user: root
tasks:
- name: Simulate long running op, allow to run for 45 sec, fire and forget
ansible.builtin.command: /bin/sleep 15
async: 45
poll: 0
如果后续任务会访问相同资源,不要对需要独占锁的操作直接使用 poll: 0,例如 yum 事务。较大的 --forks 可以更快地启动异步任务,也可提高轮询效率。
poll: 0 不会自动清理异步任务缓存。需要使用 async_status 的 mode: cleanup 手动清理。
如果后续操作需要等待异步任务,可以注册启动结果,保存任务 ID,再在后面的任务中查询其完成状态:
- 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 is finished
retries: 100
delay: 10
async 限额必须足够长。如果设置过小,后续查询可能因为状态文件还未写入或已经不存在而失败。
异步启动任务总会返回 changed。若模块需要使用 changed_when、creates 等规则标注真实变更,应把相应判断加到后续 async_status 任务中。
限制同时运行的任务数量
下面把任务分成每批两个,并在各批中等待异步任务完成,以限制并发数量:
#####################
# main.yml
#####################
- name: Run items asynchronously in batch of two items
vars:
sleep_durations:
- 1
- 2
- 3
- 4
- 5
durations: "{{ item }}"
include_tasks: execute_batch.yml
loop: "{{ sleep_durations | batch(2) | list }}"
#####################
# execute_batch.yml
#####################
- name: Async sleeping for batched_items
ansible.builtin.command: sleep {{ async_item }}
async: 45
poll: 0
loop: "{{ durations }}"
loop_control:
loop_var: "async_item"
register: async_results
- name: Check sync status
async_status:
jid: "{{ async_result_item.ansible_job_id }}"
loop: "{{ async_results.results }}"
loop_control:
loop_var: "async_result_item"
register: async_poll_results
until: async_poll_results is finished
retries: 30
main.yml 把等待时长分批传给 execute_batch.yml;后者先异步启动该批任务,再循环查询返回的任务 ID。由于每批有同步检查点,剧本不会直接启动全部批次的长任务。
进一步阅读:控制剧本执行策略、Ansible 剧本介绍、社区交流指南。
来源:Ansible 社区文档贡献者,Asynchronous actions and polling。原页 RST 源文件 位于采用 GNU GPL v3 的官方文档仓库;本稿中文整理沿用该许可。










暂无评论内容