Ansible Playbook 执行策略
设置主机执行策略
通过 strategy: 设置主机执行策略。
- name: test
hosts: all
gather_facts: false
strategy: free
tasks:
通过 ansible-doc -t strategy -l 可以查看有哪些策略插件:
[root@study ansible]# ansible-doc -t strategy -l
ansible.builtin.debug Executes tasks in interactive debug session
ansible.builtin.free Executes tasks without waiting for all hosts
ansible.builtin.host_pinned Executes tasks on each host without interruption
ansible.builtin.linear Executes tasks in a linear fashion
| strategy 名称 | 特点 | 使用场景 | Ansible 版本 |
|---|---|---|---|
linear |
默认策略,所有主机执行完某个任务后在继续执行下一个任务 | 一般情况 | 所有版本 |
free |
主机之间并发执行任务,不等其他主机完成 | 性能测试、节点独立部署 | 所有版本 |
host_pinned |
每个主机独立执行整个 play 中的所有任务(有点类似 serial: 1) |
针对节点完整生命周期操作 | Ansible 2.11+ |
debug |
每执行一步打印所有细节 | 排错场景 | 所有版本(较少用) |
-
linear:所有主机同步推进任务。
task1: host1 host2 host3 task2: host1 host2 host3 task3: host1 host2 host3 -
free:主机各自独立运行,不等待其他主机。
host1: task1 -> task2 -> task3 host2: task1 -> task2 -> task3 host3: task1 -> task2 -> task3 -
host_pinned:每台主机完整执行一遍 play,再轮到下一台主机。
host1: task1 -> task2 -> task3 | host2: └───task1 -> task2 -> task3 | host3: └───task1 -> task2 -> task3- 每个主机的 play 中所有
task、handler、rescue、always等都会执行完整流程 - 主机之间严格串行执行
- 常见于需要:
- 整台机器部署生命周期控制
- 避免并发时资源冲突
- 精准排查单主机问题
- 每个主机的 play 中所有
示例:
[root@remote-host ansible]# ansible all --list-hosts
hosts (3):
base-k8s-master-1
base-k8s-worker-1
base-k8s-worker-2
# 默认情况
[root@remote-host ansible]# cat test.yml
- name: test environment
hosts: all
gather_facts: true
#strategy: host_pinned
tasks:
- name: get env
ansible.builtin.shell: /bin/env
register: shell_result
notify: test
- name: print env
ansible.builtin.debug:
var: shell_result.rc
- name: print env1
ansible.builtin.debug:
var: shell_result.rc
handlers:
- name: test
debug:
msg: "1"
# 执行结果
[root@remote-host ansible]# ansible-playbook test.yml
PLAY [test environment] ************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [base-k8s-worker-2]
ok: [base-k8s-worker-1]
ok: [base-k8s-master-1]
TASK [get env] *********************************************************************************************************
changed: [base-k8s-worker-2]
changed: [base-k8s-worker-1]
changed: [base-k8s-master-1]
TASK [print env] *******************************************************************************************************
ok: [base-k8s-master-1] => {
"shell_result.rc": "0"
}
ok: [base-k8s-worker-1] => {
"shell_result.rc": "0"
}
ok: [base-k8s-worker-2] => {
"shell_result.rc": "0"
}
TASK [print env1] ******************************************************************************************************
ok: [base-k8s-master-1] => {
"shell_result.rc": "0"
}
ok: [base-k8s-worker-1] => {
"shell_result.rc": "0"
}
ok: [base-k8s-worker-2] => {
"shell_result.rc": "0"
}
PLAY RECAP *************************************************************************************************************
base-k8s-master-1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
base-k8s-worker-1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
base-k8s-worker-2 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
# 修改策略为 host_pinned
[root@remote-host ansible]# cat test.yml
- name: test environment
hosts: all
gather_facts: true
strategy: host_pinned
tasks:
- name: get env
ansible.builtin.shell: /bin/env
register: shell_result
notify: test
- name: print env
ansible.builtin.debug:
var: shell_result.rc
- name: print env1
ansible.builtin.debug:
var: shell_result.rc
handlers:
- name: test
debug:
msg: "1"
# 执行结果
[root@remote-host ansible]# ansible-playbook test.yml
PLAY [test environment] ************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [base-k8s-worker-2]
ok: [base-k8s-master-1]
TASK [get env] *********************************************************************************************************
changed: [base-k8s-worker-2]
TASK [print env] *******************************************************************************************************
ok: [base-k8s-worker-2] => {
"shell_result.rc": "0"
}
TASK [Gathering Facts] *************************************************************************************************
ok: [base-k8s-worker-1]
TASK [print env1] ******************************************************************************************************
ok: [base-k8s-worker-2] => {
"shell_result.rc": "0"
}
TASK [get env] *********************************************************************************************************
changed: [base-k8s-master-1]
TASK [print env] *******************************************************************************************************
ok: [base-k8s-master-1] => {
"shell_result.rc": "0"
}
TASK [print env1] ******************************************************************************************************
ok: [base-k8s-master-1] => {
"shell_result.rc": "0"
}
TASK [get env] *********************************************************************************************************
changed: [base-k8s-worker-1]
TASK [print env] *******************************************************************************************************
ok: [base-k8s-worker-1] => {
"shell_result.rc": "0"
}
TASK [print env1] ******************************************************************************************************
ok: [base-k8s-worker-1] => {
"shell_result.rc": "0"
}
PLAY RECAP *************************************************************************************************************
base-k8s-master-1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
base-k8s-worker-1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
base-k8s-worker-2 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在使用
host_pinned时,有的节点的Gathering Facts任务可能会在其他节点的任务之后执行,这个和host_pinned的单节点执行任务并不冲突,因为Gathering Facts是收集信息不会影响其他节点执行任务。我没测试,这样的话估计会影响其他节点获取这个节点的
ansible_facts变量。
设置并发数
Ansible 支持设置 Ansible 并发数(一次性最多对多少主机执行任务),并发数可以通过配置文件和 Ad-Hoc 设置:
配置文件:
[defaults]
forks = 30
Ad-Hoc:
[root@study ansible]# ansible-playbook -f 30 playbook.yml
设置批量管理主机数量
Ansible 通过队列执行任务,可以通过 serial 可以设置每个队列管理的主机数量(用于滚动更新)。
这个和 forks 不同,forks 是设置的是 Ansible 执行任务时一次性管理多少主机,serial 设置的是在 forks 基础上一个队列里最多有多少个主机执行任务。
serial 支持数量、百分比和列表三种种方式。
数量:
- name: test
hosts: all
serial: 1
一个队列执行一个主机。
百分比:
- name: test
hosts: all
serial: 30%
一个队列执行 30% 的主机(向下取整,最少一台)。
列表:
- name: test
hosts: all
serial:
- 1
- 5
- 10
- name: test
hosts: all
serial:
- 10%
- 20%
- 100%
第一个表示:
- 第一次队列执行 1 台
- 第二次队列执行 5 台
- 后续的队列每次 10 台
第二个表示(假设 hosts 为 all 有 10 台):
- 第一次队列执行
all的 10% 的主机(1 台) - 第二次队列执行
all的 20% 的主机(2 台) - 第三次队列执行
all的剩余所有主机(7 台)
列表还可以组合使用:
- name: test
hosts: all
serial:
- 1
- 5
- 20%
第一次 1 台,第二次 5 台,后续每次 20%。
限制单个任务执行数量
forks 和 serial 都是在 Playbook 级别限制,如果想在一个 tasks 上限制可以使用 throttle,不过这个可能占用大量 CPU 资源。
throttle 支持在 tasks 和 block 上设置。
tasks:
- command: /path/to/cpu_intensive_command
throttle: 1
如果将
throttls和forks或serial同时使用,则throttle要小于它俩。
设置主机执行顺序
通过 order 可以设置主机执行顺序,order 有如下几个选项:
inventory:根据 Ansible 编译后的主机清单执行,主机顺序可预测但不可重现reverse_inventory:和inventory相反sorted:根据字母顺序排序reverse_sorted:跟sorted相反shuffle:随机排序
- name: test
hosts: all
order: sorted
设置任务只执行一次
通过 run_once 可以设置任务只执行一次(只在当前队列的第一台主机上执行
),通常与 delegate_to 组合使用,实现只在某个节点执行任务。
- name: run_once
ansible.builtin.debug:
msg: "run_once"
run_once: true