Ansible 异步操作与轮询

默认情况下,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 的官方文档仓库;本稿中文整理沿用该许可。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容