控制剧本执行:策略和更多

默认情况下,Ansible 使用 5 个分叉,在开始在任何主机上执行下一个任务之前,在受剧本影响的所有主机上运行每个任务。如果你想更改此默认行为,可以使用不同的策略插件,更改分叉数量,或应用 serial 等多个关键字之一。

选择策略

上面描述的默认行为是 线性策略。Ansible 提供其他策略,包括 调试策略(另请参见 调试任务)和 自由策略,它允许每个主机以最快的速度运行到剧本结束。

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

你可以如上所示为每个剧本选择不同的策略,或者在 ansible.cfg 中的 defaults 部分设置你首选的全局策略。

[defaults]
strategy = free

所有策略都作为 策略插件 实现。请查看每个策略插件的文档,了解其工作原理的详细信息。

设置分叉数量

如果你有足够的处理能力并且想要使用更多分叉,可以在 ansible.cfg 中设置数量。

[defaults]
forks = 30

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

使用关键字控制执行

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

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

使用 serial 设置批次大小

默认情况下,Ansible 会并行地在你在每个剧本的 hosts: 字段中设置的 模式 中的所有主机上运行。如果你想一次只管理几台机器,例如在滚动更新期间,可以使用 serial 关键字定义 Ansible 应该一次管理多少台主机。

---
- name: test play
  hosts: webservers
  serial: 3
  gather_facts: False

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

在上面的例子中,如果我们在 “webservers” 组中有 6 台主机,Ansible 将在 3 台主机上完全执行剧本(两个任务),然后继续执行接下来的 3 台主机。

PLAY [webservers] ***********************************************************************

TASK [first task] ***********************************************************************
changed: [web1]
changed: [web3]
changed: [web2]

TASK [second task] **********************************************************************
changed: [web1]
changed: [web2]
changed: [web3]

PLAY [webservers] ***********************************************************************

TASK [first task] ***********************************************************************
changed: [web4]
changed: [web5]
changed: [web6]

TASK [second task] **********************************************************************
changed: [web4]
changed: [web5]
changed: [web6]

PLAY RECAP ******************************************************************************
web1                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web2                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web3                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web4                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web5                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
web6                       : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

注意

使用 serial 设置批次大小会将 Ansible 失败范围更改为批次大小,而不是整个主机列表。可以使用 ignore_unreachablemax_fail_percentage 修改此行为。

你还可以使用 serial 关键字指定百分比。Ansible 将百分比应用于剧本中的主机总数,以确定每次通过的主机数量。

---
- name: test play
  hosts: webservers
  serial: "30%"

如果主机数量不能被通过次数平均分配,则最后一趟将包含余数。在这个例子中,如果你在 webservers 组中有 20 台主机,第一批将包含 6 台主机,第二批将包含 6 台主机,第三批将包含 6 台主机,最后一批将包含 2 台主机。

你还可以将批次大小指定为列表。例如

---
- name: test play
  hosts: webservers
  serial:
    - 1
    - 5
    - 10

在上面的例子中,第一批将包含一台主机,下一批将包含 5 台主机,(如果有任何主机剩余),每批之后将包含 10 台主机或所有剩余的主机(如果剩余少于 10 台主机)。

你可以在列表中列出多个批次大小作为百分比。

---
- name: test play
  hosts: webservers
  serial:
    - "10%"
    - "20%"
    - "100%"

你也可以混合使用这些值。

---
- name: test play
  hosts: webservers
  serial:
    - 1
    - 5
    - "20%"

注意

无论百分比多么小,每次通过的主机数量总是 1 或更大。

使用 throttle 限制执行

throttle 关键字限制特定任务的工作进程数量。它可以在块和任务级别设置。使用 throttle 来限制可能占用大量 CPU 或与限速 API 交互的任务。

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

如果你已经限制了分叉数量或并行执行的主机数量,你可以使用 throttle 减少工作进程数量,但不能增加它。换句话说,要产生影响,你的 throttle 设置必须低于你的 forksserial 设置(如果你同时使用它们)。

根据清单排序执行

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

inventory

(默认)清单为请求的选择提供的顺序(见下文说明)

reverse_inventory

与上面相同,但反转返回的列表

sorted

按名称字母排序

reverse_sorted

按名称反向字母排序

shuffle

每次运行时随机排序

注意

“清单”顺序不等同于在清单源文件中定义主机/组的顺序,而是“从已编译清单中返回选择的顺序”。这是一个向后兼容的选项,虽然可重现,但通常不可预测。由于清单、主机模式、限制、清单插件以及允许使用多个源代码的特性,几乎不可能返回这样的顺序。对于简单的情况,这可能会碰巧与文件定义顺序匹配,但这不能保证。

使用 run_once 在单个机器上运行

如果你希望一个任务只在当前批次中的第一台主机上运行,请将该任务的 run_once 设置为 true。

---
# ...

  tasks:

    # ...

    - command: /opt/application/upgrade_db.py
      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 的任务将在每个串行批次中的一个主机上运行。如果任务必须无论 serial 模式如何都只运行一次,请使用 when: inventory_hostname == ansible_play_hosts_all[0] 结构。

注意

任何条件语句(换句话说,when:)都将使用“第一个主机”的变量来决定任务是否运行,不会测试其他主机。

注意

如果您希望避免将事实设置为所有主机的默认行为,请为特定任务或块设置 delegate_facts: True

另请参阅

Ansible 剧本

剧本简介

控制任务运行的位置:委托和本地操作

在特定机器上运行任务或分配事实

角色

按角色组织剧本

通信

有问题?需要帮助?想分享你的想法?请访问 Ansible 通信指南