我使用的是 Ansible 2.9 和 AWX 11。我有一组服务器,其中一些可以通过遵循类似 的模式的标签进行逻辑细分GUID_1234567890
。每个唯一标签代表任意数量的服务器GUID_*
。除了GUID_*
标签之外,服务器还将被标记为foo
或bar
。
更具体地说,我有 2,000 台服务器,其中 1,000 台带有 80 个唯一标签GUID_*
。在这 80 个唯一GUID_*
服务器组中,我必须重启带有 标记的服务器foo
,但不必重启带有 标记的服务器bar
。此外,如果服务器具有相同的标签,我必须foo
依次重启它们GUID_*
。
我可以启动一个具有如下主机模式的剧本:hosts: GUID_*:&foo
并获取所有GUID_
标记的foo
主机。但是,如果剧本的serial:
选项不是1
,则 foo 服务器将并行重新启动,很可能是同一GUID_
标记组中的多个 foo 服务器。如果按顺序执行,剧本可能需要一天以上才能完成。我想使用 Ansible 的分叉为 80 组主机中的每一组运行剧本的分叉GUID_*
,但每个分叉都必须调用一个serial:1
针对foo
服务器运行的剧本。
有没有办法从大量主机开始,然后创建并行工作器来serial: 1
为一部分主机执行剧本?
答案1
单个剧本无法实现目标。如果要并行处理各个组,则需要为每个组提供专用的剧本。使用 Ansible 创建代码。
“主机子集较小“
给出库存以简化测试
test_01
test_02
test_03
test_04
test_05
test_06
[GUID_01]
test_01
test_02
test_03
[GUID_02]
test_04
test_05
test_06
[foo]
test_01
test_02
test_04
test_05
srvX
[bar]
test_03
test_06
srvY
创建所有词典GUID_*以及主机列表,特别是GUID_x和富组。例如
- hosts: GUID_*:&foo
gather_facts: false
tasks:
- set_fact:
my_groups: "{{ my_groups|default({})|
combine({item: my_hosts|dict2items|
selectattr('value', 'eq', item)|
map(attribute='key')|list}) }}"
loop: "{{ my_guids|unique }}"
vars:
my_guids: "{{ ansible_play_hosts_all|
map('extract', hostvars, 'group_names')|
map('select', 'match', 'GUID')|
map('first')|flatten }}"
my_hosts: "{{ dict(ansible_play_hosts_all|zip(my_guids)) }}"
run_once: true
- debug:
var: my_groups
run_once: true
给出
my_groups:
GUID_01:
- test_01
- test_02
GUID_02:
- test_04
- test_05
无需创建相同的词典模式
- hosts: all
gather_facts: false
tasks:
- set_fact:
my_groups: "{{ my_groups|default({})|
combine({item: groups[item]|
intersect(groups['foo'])}) }}"
loop: "{{ groups|select( 'match', 'GUID')|list }}"
run_once: true
问:“创建执行串行的并行工作器:为部分主机创建 1 个剧本。“
答:使用 Ansible 模板创建代码。例如,给定角色
shell> cat roles/reboot/tasks/main.yml
- command: date "+%H:%M:%S"
register: result
- debug:
msg: "{{ result.stdout }} {{ inventory_hostname }} Reboot"
- command: sleep 3
- command: date "+%H:%M:%S"
register: result
- debug:
msg: "{{ result.stdout }} {{ inventory_hostname }} Ready"
模板
shell> cat templates/my_hosts.j2
{{ lookup('file', 'hosts') }}
# ---------------------------------------------------------------------
# Groups for my_wrapper. See template my_hosts.j2
{% for group,hosts in my_groups.items() %}
[my_{{ group }}]
{% for host in hosts %}
{{ host }}
{% endfor %}
{% endfor %}
shell> cat templates/my_pb.j2
- hosts: my_{{ item }}
gather_facts: false
serial: 1
roles:
- reboot
shell> cat templates/my_wrapper.j2
#!/bin/bash
{% for group,hosts in my_groups.items() %}
nohup ansible-playbook -i my_hosts my_pb_{{ group }}.yml &
{% endfor %}
和剧本
- hosts: all
gather_facts: false
tasks:
- set_fact:
my_groups: "{{ my_groups|default({})|
combine({item: groups[item]|
intersect(groups['foo'])}) }}"
loop: "{{ groups|select( 'match', 'GUID')|list }}"
run_once: true
- block:
- template:
src: my_hosts.j2
dest: my_hosts
- template:
src: my_wrapper.j2
dest: my_wrapper.sh
mode: "a+x"
- template:
src: my_pb.j2
dest: "my_pb_{{ item }}.yml"
loop: "{{ my_groups.keys()|list }}"
run_once: true
delegate_to: localhost
使用代码创建文件
shell> cat my_hosts
...
# ---------------------------------------------------------------------
# Groups for my_wrapper. See template my_hosts.j2
[my_GUID_01]
test_01
test_02
[my_GUID_02]
test_04
test_05
shell> cat my_wrapper.sh
#!/bin/bash
nohup ansible-playbook -i my_hosts my_pb_GUID_01.yml &
nohup ansible-playbook -i my_hosts my_pb_GUID_02.yml &
shell> cat my_pb_GUID_01.yml
- hosts: my_GUID_01
gather_facts: false
serial: 1
roles:
- reboot
shell> cat my_pb_GUID_02.yml
- hosts: my_GUID_02
gather_facts: false
serial: 1
roles:
- reboot
然后,运行包装器得到
shell> grep msg nohup.out
"msg": "13:03:51 test_01 Reboot"
"msg": "13:03:51 test_04 Reboot"
"msg": "13:03:56 test_01 Ready"
"msg": "13:03:56 test_04 Ready"
"msg": "13:03:58 test_02 Reboot"
"msg": "13:03:58 test_05 Reboot"
"msg": "13:04:04 test_02 Ready"
"msg": "13:04:04 test_05 Ready"