控制 playbook 的执行:策略及其他

默认情况下,在所有受某个 play 影响的主机上,Ansible 都会在启动下一个任务前,使用 5 个(进程)分叉运行每个任务。若咱们想要更改这种默认行为,咱们可使用别的策略插件、更改分叉数,或使用 serial 等几个关键字之一。

选取策略

上面讲到的默认行为,即为 线性策略。Ansible 提供了其他策略,包括 调试策略(另请参阅 “调试任务”)和 自由策略,后者允许每台主机以最快速度运行,直到 play 的结束处:

- hosts: all
  strategy: free
  tasks:
  # ...

如上所示,咱们可为每个 play 选择不同策略,也可在 ansible.cfg 中的 defaults 小节中,全局设置咱们所偏好的策略:

[defaults]
strategy = free

所有策略都是以 策略插件 实现的。请查看每种策略插件的文档,了解其工作原理。

设置分叉数

若咱们有足够的进程处理能力,并希望使用更多的进程分叉,可在 ansible.cfg 中设置该数量:

[defaults]
forks = 30

或在命令行上传递:ansible-playbook -f 30 my_playbook.yml

使用关键字控制执行

除策略外,还有几个 Ansible 关键字,也会影响 play 的执行。咱们可使用 serial 关键字,设置咱们一次要管理的主机数量、百分比或数量列表。在开始下一批主机之前,Ansible 会在指定数量或百分比的主机上完成该 play。咱们可使用 throttle 关键字,限制分配给某个区块或任务的工作进程数量,the number of workers。使用 order 关键字,咱们可以控制 Ansible 如何在一组主机中选择下一要执行的主机。咱们可以使用 run_once 关键字,在单个主机上运行某个任务。这些关键字不属于策略。他们是应用到 play、区块或任务的一些指令或选项。

其他影响 play 执行的关键字包括 ignore_errorsignore_unreachableany_errors_fatal。这些选项在 playbook 中的错误处理 中有详细说明。

使用 serial 关键字设置批次大小

默认情况下,Ansible 会针对咱们在 hosts: 字段中,所设置 模式 中的所有主机,并行运行各个 play。若咱们打算一次只管理少量机器,例如在滚动更新期间,则可使用 serial 关键字,定义 Ansible 单次应管理多少台主机:

---
- name: test play
  hosts: all:!win10-133
  serial: 2
  gather_facts: False

  tasks:
    - name: first task
      command: hostname
    - name: second task
      command: hostname

在上面的示例中,我们使用 'all:!win10-133' 排除了 'all' 中的 Windows 主机 'win10-133',剩下 5 台主机,Ansible 会在其中 2 台主机上完全执行该 play(两个任务),然后再执行接下来的 2 台主机,最后执行 1 台主机:

PLAY [test play] *******************************************************************************************************************

TASK [first task] ******************************************************************************************************************
changed: [debian-199]
changed: [almalinux-5]

TASK [second task] *****************************************************************************************************************
changed: [debian-199]
changed: [almalinux-5]

PLAY [test play] *******************************************************************************************************************

TASK [first task] ******************************************************************************************************************
changed: [almalinux-61]
changed: [almalinux-39]

TASK [second task] *****************************************************************************************************************
changed: [almalinux-39]
changed: [almalinux-61]

PLAY [test play] *******************************************************************************************************************

TASK [first task] ******************************************************************************************************************
changed: [almalinux-207]

TASK [second task] *****************************************************************************************************************
changed: [almalinux-207]

PLAY RECAP *************************************************************************************************************************
almalinux-207              : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
almalinux-39               : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
almalinux-5                : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
almalinux-61               : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
debian-199                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

注意:以 serial 关键字,设置了批次大小,会将 Ansible 失败范围改为该批次大小,而不是整个主机列表。咱们可使用 ignore_unreachablemax_fail_percentage 选项,修改这一行为。

咱们也可用 serial 键字指定一个百分比。Ansible 会将该百分比应用到 play 中的主机总数,以确定出每次要传递的主机数量:

---
- name: test play
  hosts: all:!win10-133
  serial: "30%"

如果主机数量未被每次传递数量整除,那么最后一次传递,将包含剩余部分。在本例中,如果模式 all:!win10-133 中有 20 台主机,那么第一批将包含 6 台主机,第二批将包含 6 台,第三批将包含 6 台,最后一批将包含 2 台主机。

咱们还可将批次大小,指定为一个列表。例如:

---
- name: test play
  hosts: all:!win10-133
  serial:
    - 1
    - 2
    - 2

在上面的示例中,第一批将包含一台主机,下一批将包含 2 台主机,(如还剩有主机),接下来的每一批都将包含 2 台主机或所有剩余的主机(如剩余的主机少于 2 台)。

咱们可将多个批次大小,以百分比方式列出:

---
- name: test play
  hosts: all:!win10-133
  serial:
    - "20%"
    - "40%"
    - "100%"

咱们还可以将这些值混用与匹配:

---
- name: test play
  hosts: all:!win10-133
  serial:
    - 1
    - 2
    - "20%"

注意:不论百分比有多小,每次传递的主机数量将总是 1 或更多。

throttle 关键字限制执行

throttle 关键字可限制某个特定任务的工作进程数量。他可在区块与任务级别设置。使用 throttle 可限制那些 CPU 密集型,或要与某个存在限速 API 交互的任务:

  tasks:
  - command: /path/to/cpu_intensive_command
    throttle: 1

在咱们已经限制了进程分叉数,或要并行执行的机器数时,咱们可以使用 throttle 减少工作进程数量,但不能增加。换句话说,要产生效果,在三者同时使用时,咱们的 throttle 设置必须低于 forksserial 设置。

根据仓库对执行排序

order 关键字控制了主机的运行顺序。顺序的可能值有:

  • inventory (默认值)由仓库为所请求的选择,提供的顺序(见下文注意事项);

  • reverse_inventory 与上面的相同,但逆转了返回的列表;

  • sorted 按主机名的字母排序;

  • reverse_sorted 按名字的字母倒序排列;

  • shuffle 每次运行时随机排序。

注意'inventory' 这种顺序,并不等同于在仓库源文件中,所定义的主机/分组顺序,而是 ”自编译后清单所返回的某个选择的顺序"。这是个向后兼容选项,尽管可以重现,但通常无法预测。由于仓库的性质、主机模式、限制、仓库插件及允许多种来源的能力等因素,几乎不可能返回这样的顺序。对于一些简单情形,这可能会与文件定义的顺序相匹配,但这并不能保证。

使用 run_once 在单台机器上运行

如果咱们想要某个任务,只在一批主机中的第一台主机上运行,就要在该任务上设置 run_oncetrue

---
- name: test play
  hosts: all:!win10-133
  gather_facts: False

  tasks:
    - name: first task
      command: hostname
      run_once: true

Ansible 会在当前批次的第一台主机上执行这个任务,并将所有结果和事实,应用到同一批次的所有主机上。这种方法类似于应用一项条件到某个任务,例如:

    - command: /opt/application/upgrade_db.py
      when: inventory_hostname == webservers[0]

不过在 run_once 下,任务结果会应用到所有主机。要在特定主机而不是批次中第一台主机上运行该任务,就要委派该任务:

    - command: /opt/application/upgrade_db.py
      run_once: true
      delegate_to: web01.example.org

一如 委派 那样,该操作将在那台受委派的主机上执行,但有关信息仍是该任务中,原始主机的信息。

注意:在 serial 关键字一起使用时,标记为 run_once 的任务,将在 每个 序列批次中的一台主机上运行。若要该任务在无论序列模式为何下,必须都只运行一次,就要使用: inventory_hostname == ansible_play_hosts_all[0] 的结构。

注意:任意条件(也就是 when:),将使用 'first host' 的变量,决定该任务是否要运行,而不会测试其他主机。

注意:若咱们想要避免给所有主机设置事实的这种默认行为,就要这个特定任务或区块,设置 delegate_facts: True

(End)

Last change: 2025-02-13, commit: cb34bb4

小额打赏,赞助 xfoss.com 长存......

微信 | 支付宝

若这里内容有帮助到你,请选择上述方式向 xfoss.com 捐赠。