Ansible 剧本从大型分叉主机列表开始,但为较小的主机子集生成串行任务

Ansible 剧本从大型分叉主机列表开始,但为较小的主机子集生成串行任务

我使用的是 Ansible 2.9 和 AWX 11。我有一组服务器,其中一些可以通过遵循类似 的模式的标签进行逻辑细分GUID_1234567890。每个唯一标签代表任意数量的服务器GUID_*。除了GUID_*标签之外,服务器还将被标记为foobar

更具体地说,我有 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"

相关内容