首页 > 解决方案 > 使用 ansible 与多个组和服务器一起播放和执行任务

问题描述

我们有这个包含数十台服务器的 Ansible 清单,按微服务分组在服务器中。假设我们在清单中有几个应用程序组,其中包含服务器。

说:

[group1]
server1
server2
server3
server20
server27
server38

[group2]
server4
server5

[group3]
server7
server8
server9
server6

该库存已用于数十场比赛,因此仅更改它不是一种选择。我需要处理这个设置。

我需要知道是否有可能以某种方式在每个组的一台服务器上并行运行一个剧本而不在剧本中明确命名它们?(组和服务器可以由其他人添加,我需要玩才能应付)

因此,当播放开始时,它可能会在 server1、server4 和 server7 上并行处理。server2 上的处理可能在 server1 完成时开始,server5 的处理可能在 server4 完成时开始,等等。你明白我的意思。这将意味着,在开始时,每个组的一个服务器被处理,但随着时间的推移,较小的组将完成,而在较大的组中仍然会进行处理。

有没有办法做到这一点?

蒂亚

标签: parallel-processingansibleexecutioninventory

解决方案


问:在每个组中的 1 台服务器上并行运行......在 server1、server4 和 server7 上并行处理。server1 完成时可能会开始 server2 上的处理,当 server4 完成时可能会开始 server5 的处理,等等......迭代编写代码时未知的多个组和服务器。

A:作为一个不完整的提示,下面的剧本

- hosts: all
  gather_facts: false
  vars:
    _groups: "{{ groups.keys()|difference(['all', 'ungrouped']) }}"
#   _hosts: [0, 1, 2]  # Range of minimal common leght perhaps?
    _groups_len_min: "{{ _groups|map('extract', groups)|map('length')|min }}"
    _hosts: "{{ range(_groups_len_min|int) }}"
    my_hosts: "{{ query('cartesian', _hosts, _groups) }}"
  tasks:
    - add_host:
        name: "{{ groups[item.1][item.0] }}"
        groups: my_group
      loop: "{{ my_hosts }}"
      run_once: true

- hosts: my_group
  gather_facts: false
  serial: 3  # TODO: Number of the groups involved
  order: inventory
  tasks:
    - debug:
        var: inventory_hostname

PLAY [my_group] ***************************************************

TASK [debug] ******************************************************
ok: [server4] => 
  inventory_hostname: server4
ok: [server1] => 
  inventory_hostname: server1
ok: [server7] => 
  inventory_hostname: server7

PLAY [my_group] ***************************************************

TASK [debug] ******************************************************
ok: [server2] => 
  inventory_hostname: server2
ok: [server5] => 
  inventory_hostname: server5
ok: [server8] => 
  inventory_hostname: server8

PLAY [my_group] ***************************************************

TASK [debug] ******************************************************
ok: [server6] => 
  inventory_hostname: server6
ok: [server3] => 
  inventory_hostname: server3
ok: [server9] => 
  inventory_hostname: server9

如果你想包括所有主机,用假人填充缺失的主机,例如给定库存

shell> cat hosts
[group1]
server1
server2
server3

[group2]
server4
server5

[group3]
server7

剧本

- hosts: all
  gather_facts: false
  vars:
    _groups: "{{ groups.keys()|difference(['all', 'ungrouped']) }}"
    _groups_len_max: "{{ _groups|map('extract', groups)|map('length')|max }}"
    _hosts: "{{ range(_groups_len_max|int) }}"
    my_hosts: "{{ query('cartesian', _hosts, _groups) }}"
  tasks:
    - add_host:
        name: "{{ groups[item.1][item.0]|default('dummy-' ~ ansible_loop.index) }}"
        groups: my_group
      loop: "{{ my_hosts }}"
      loop_control:
        extended: true
      run_once: true

- hosts: my_group
  gather_facts: false
  serial: 3  # TODO: Number of the groups involved
  order: inventory
  tasks:
    - name: Proceed if not dummy
      block:
        - debug:
            var: inventory_hostname
      when: inventory_hostname is not match('^dummy-\d*$')

PLAY [my_group] *****************************************************

TASK [debug] ********************************************************
ok: [server1] => 
  inventory_hostname: server1
ok: [server4] => 
  inventory_hostname: server4
ok: [server7] => 
  inventory_hostname: server7

PLAY [my_group] *****************************************************

TASK [debug] ********************************************************
skipping: [dummy-6]
ok: [server2] => 
  inventory_hostname: server2
ok: [server5] => 
  inventory_hostname: server5

PLAY [my_group] *****************************************************

TASK [debug] ********************************************************
ok: [server3] => 
  inventory_hostname: server3
skipping: [dummy-8]
skipping: [dummy-9]

笔记

一个简单的选择是创建动态组,例如

- hosts: all
  gather_facts: false
  vars:
    my_groups:
      my_group1: [[group1,0], [group2,0], [group3,0]]
      my_group2: [[group1,1], [group2,1], [group3,1]]
      my_group3: [[group1,2], [group2,2], [group3,2]]
  tasks:
    - add_host:
        name: "{{ groups[item.1.0][item.1.1] }}"
        groups: "{{ item.0.key }}"
      with_subelements:
        - "{{ my_groups|dict2items }}"
        - value
      run_once: true

- hosts: my_group1
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

- hosts: my_group2
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

- hosts: my_group3
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

给出(删节)

PLAY [my_group1] *******************************************************

TASK [debug] ***********************************************************
ok: [server1] => 
  inventory_hostname: server1
ok: [server7] => 
  inventory_hostname: server7
ok: [server4] => 
  inventory_hostname: server4

PLAY [my_group2] *******************************************************

TASK [debug] ***********************************************************
ok: [server5] => 
  inventory_hostname: server5
ok: [server2] => 
  inventory_hostname: server2
ok: [server8] => 
  inventory_hostname: server8

PLAY [my_group3] *******************************************************

TASK [debug] ***********************************************************

ok: [server3] => 
  inventory_hostname: server3
ok: [server6] => 
  inventory_hostname: server6
ok: [server9] => 
  inventory_hostname: server9

下一个选项是创建具有所需主机顺序的单个组并设置serialorder,例如

- hosts: all
  gather_facts: false
  vars:
    my_groups:
      my_group1: [[group1,0], [group2,0], [group3,0]]
      my_group2: [[group1,1], [group2,1], [group3,1]]
      my_group3: [[group1,2], [group2,2], [group3,2]]
  tasks:
    - add_host:
        name: "{{ groups[item.1.0][item.1.1] }}"
        groups: my_group
      with_subelements:
        - "{{ my_groups|dict2items }}"
        - value
      run_once: true

- hosts: my_group
  gather_facts: false
  serial: 3
  order: inventory
  tasks:
    - debug:
        var: inventory_hostname

给出(删节)

PLAY [my_group] ****************************************************

TASK [debug] *******************************************************
ok: [server1] => 
  inventory_hostname: server1
ok: [server7] => 
  inventory_hostname: server7
ok: [server4] => 
  inventory_hostname: server4

PLAY [my_group] ****************************************************

TASK [debug] *******************************************************
ok: [server2] => 
  inventory_hostname: server2
ok: [server5] => 
  inventory_hostname: server5
ok: [server8] => 
  inventory_hostname: server8

PLAY [my_group] ****************************************************

TASK [debug] *******************************************************
ok: [server3] => 
  inventory_hostname: server3
ok: [server6] => 
  inventory_hostname: server6
ok: [server9] => 
  inventory_hostname: server9

为了避免手动编写大型矩阵的繁琐工作,可以动态创建结构,例如下面的播放创建相同的动态组

- hosts: all
  gather_facts: false
  vars:
    _groups: [group1, group2, group3]
    _hosts: [0, 1, 2]
    _dgroups: [my_group1, my_group2, my_group3]
    _groups_hosts: "{{ query('cartesian', _hosts, _groups)|
                       batch(_dgroups|length) }}"
    my_groups: "{{ dict(_dgroups|zip(_groups_hosts)) }}"
  tasks:
    - add_host:
        name: "{{ groups[item.1.1][item.1.0] }}"
        groups: my_group
      with_subelements:
        - "{{ my_groups|dict2items }}"
        - value
      run_once: true

推荐阅读