根据 ansible 中的名称子集选择清单中的主机

根据 ansible 中的名称子集选择清单中的主机

我对 ansible 还很陌生,所以这也许很容易做到。

我们有大量的设备在不同的环境中具有一致的命名约定。

app0[01:25].dev.domain.com
app[01:25].qa.domain.com
app[01:25].uat.domain.com
app[01:25].prod.domain.com

这些应用服务器中的各种设备具有特定角色,如 Web 服务器、应用服务器、API 服务器等,并且跨环境都相同。因此,app05 是 dev、qa、uat、uat、prod 中的 Web 服务器。

现在我正在使用 group_vars 并为组名分配特定的服务器角色。但我不想为每个环境设置组名(webdev、webqa、webuat 等)

有没有简单的解决方案?我认为角色会让事情变得有点复杂,但也许这就是解决方案?

答案1

问:为每个环境设置组名(webdev、webqa、webuat 等)

答:动态创建变量,例如

- hosts: all
  gather_facts: false
  vars:
    env:
      app05: web
  tasks:
    - set_fact:
        env_local: "{{ env[_host]|d('none') }}{{ _group }}"
      vars:
        _arr: "{{ inventory_hostname.split('.') }}"
        _host: "{{ _arr.0 }}"
        _group: "{{ _arr.1 }}"
    - debug:
        var: env_local

给出

ok: [app01.dev.domain.com] => 
  env_local: nonedev
ok: [app02.dev.domain.com] => 
  env_local: nonedev
ok: [app03.dev.domain.com] => 
  env_local: nonedev
ok: [app04.dev.domain.com] => 
  env_local: nonedev
ok: [app05.dev.domain.com] => 
  env_local: webdev

使用模块添加主机并动态创建组。例如,创建文件

shell> cat add_host_to_groups.yml
- add_host:
    name: "{{ i }}"
    groups: "{{ item }}{{ (i.split('.')).1 }}"
  loop: "{{ _hosts }}"
  loop_control:
    loop_var: i

并将其包含在分配规则的循环中

- hosts: all
  gather_facts: false
  vars:
    env:
      web: app05
  tasks:
    - include_tasks: add_host_to_groups.yml
      loop: "{{ env.keys()|list }}"
      vars:
        _hosts: "{{ ansible_play_hosts_all|select('match', env[item] ~ '.*') }}"
      run_once: true
    - debug:
        var: groups
      run_once: true

给出

  groups:
    all:
    - app01.dev.domain.com
    - app02.dev.domain.com
    - app03.dev.domain.com
      ...
    - app25.prod.domain.com
    webdev:
    - app05.dev.domain.com
    webprod:
    - app05.prod.domain.com
    webqa:
    - app05.qa.domain.com
    webuat:
    - app05.uat.domain.com

在连续的游戏中使用这些组,例如

- hosts: webqa
  gather_facts: false
  tasks:
    - debug:
        var: ansible_play_hosts_all

给出

  ansible_play_hosts_all:
  - app05.qa.domain.com

适合字典环境满足您的需求。

答案2

建立真实来源的清单方案是从某个系统查询这些组。比 DNS 名称中的字符串更复杂的东西。

例如,netbox 库存数据库系统有一个可以适应的设备角色。不是要挑剔 netbox,而是它有一个 Ansible 库存插件和一个开放的数据库模型,所以很容易谈论。


但是,也许还没有一个好的外部数据库。可以生成这样的常规命名方案。使用 Ansible 库存插件中最递归的生成器:

# inventory.yml
plugin: generator
hosts:
    name: "{{ application }}{{ number }}.{{ environment }}.example.com"
    parents:
      - name: "{{ application }}_{{ environment }}"
        parents:
          - name: "{{ application }}"
            vars:
              application: "{{ application }}"
          - name: "{{ environment }}"
            vars:
              environment: "{{ environment }}"
layers:
    application:
        - app
        - api
    environment:
        - dev
        - qa
        - uat
        - prod
    number:
        - "01"
        - "02"
        - "05"

层名称是任意的。给定“主机”根和“父级”符号,更深的缩进名称是包含外部名称的组。

ansible-inventory -i inventory.yml --list 将在 Ansible 的清单 JSON 文档中打印主机。部分输出:

{
    "_meta": {
        "hostvars": {

           "app05.qa.example.com": {
                "application": "app",
                "environment": "qa"
            }
        }
    },

    "app_qa": {
        "hosts": [
            "app01.qa.example.com",
            "app02.qa.example.com",
            "app05.qa.example.com"
        ]
    },

    "app": {
        "children": [
            "app_dev",
            "app_prod",
            "app_qa",
            "app_uat"
        ]
    },

    "qa": {
        "children": [
            "api_qa",
            "app_qa"
        ]
    },


}

并继续进行其他组合。

注意它做了:

  • “应用程序”组
  • “环境” 组
  • “应用环境”组合组
  • 符合 DNS 名称模式的主机名
  • 包含每个主机的“应用程序”和“环境”的变量

该插件的局限性包括:

始终对图层组合进行笛卡尔积运算。某个组不能多或少,也不能以不同的值开始编号方案。

没有紧凑的主机范围。[01:25] 语法和 range() 函数都不起作用。请考虑通过提交问题来请求。作为一种解决方法,配置文件中的数十个数字是有用的。

相关内容