首页 文章

Ansible:定义playbook“default”vars,优先考虑角色,但在库存中可以覆盖

提问于
浏览
1

TL; DR

使用Ansible我试图在playbook级别定义某种默认变量 - 让我们称之为playbook默认值 - 它优先于其他角色默认值但可以被库存库存group_vars /所有变量覆盖 .

如何定义某种类型的playbook默认变量,这些变量优先于其他角色默认但可被库存(环境)覆盖?


目前Ansible 2.x变量优先级如下:

role defaults inventory files或script group vars inventory group_vars / all playbook group_vars / all

我希望实现的是:

角色默认值playbook默认库存文件或脚本组vars inventorygroup_vars / all playbook group_vars / all

从我之前使用的大多数工具和应用程序中,在环境级别定义的变量(dev,test,QA,prod等)优先于其他“应用程序”变量,这些变量本身优先于其他“外部”组件 . 其他优先顺序是:

  • "External" components vars(来自Galaxy的角色)

  • "Application" vars(Playbook vars)

  • "Environment" vars(开发,测试等)

环境最优先 . 但我找不到用Ansible重现这种模式的方法 . 这样的事情很容易在Chef(外部cookbook默认被包装器cookbook默认覆盖)和Puppet,但我找不到与Ansible实现相同的方法 .

具有简单应用程序的示例

让我们考虑一个由与Web服务器交互的多个服务组成的应用程序 . 这些服务是通用的,并在我的组织的其他部分重用,但在我的情况下,我使用了apache2 . 我有这些角色:

  • apache

  • green_service

  • blue_service

  • red_service

这些默认变量:

# roles/apache/defaults/main.yml
apache_listen_port: 80

# roles/green_service/defaults/main.yml
green_service_port: 80

# roles/blue_service/defaults/main.yml
blue_service_port: 80

# roles/red_service/defaults/main.yml
red_service_port: 80

每个服务必须知道apache端口,这在默认情况下表示 . 如果其他应用程序需要使用Nginx或其他Web服务器的绿色服务,则只需包含相关角色 .

现在,如果我想在一个或多个环境中从80 ot 8081更改端口怎么办?

“直截了当”的方式

..我最终不得不在每个环境中复制所有这些变量,例如:

# production/group_vars/all/all.yml
apache_listen_port: 8081
green_service_port: 8081
blue_service_port: 8081
red_service_port: 8081

# ... and so on in each environments inventory!

在这个简单的例子中,这可能没问题,但是当你有5个环境的10个服务时,它就变成了一场噩梦......更新一个简单的变量可能会对很多服务产生影响,而且很难维护和理解 .

公寓从答案"Your service design may be wrong..."我正在寻找避免这种情况的方法 .

我想要实现的目标

我想要实现的是能够在playbook级别表示我的服务和web服务器之间的变量链接,例如:

# somewhere in my playbook .yml
# these variables override roles default
# but can be overriden in my inventories
myapp_port: 80

apache_listen_port: "{{ myapp_port }}"
green_service_port: "{{ myapp_port }}"
blue_service_port: "{{ myapp_port }}"
red_service_port: "{{ myapp_port }}"

现在在每个环境中我只需要覆盖一个且只有一个变量,例如:

# production/group_vars/all/all.yml
myapp_port: 8081

我没有找到一种合理的方法,没有过度复杂化我的剧本来实现类似的东西 .

使用Ansible,有没有一种正确的方法来完成这个Playbook vars优先于其他Defaults vars而不是Inventories vars?

1 回答

  • 1

    请记住,在Ansible中, {{ ... }} 表达式通常以惰性方式进行模板化(除了 set_fact ),因此您不是"assign"变量,而是告诉Ansible如何在运行时获取该值 .

    如果您可以控制角色:

    你可以 roles/apache/defaults/main.yml

    apache_listen_port: "{{ myapp_port | default(80) }}"
    

    roles/green_service/defaults/main.yml

    green_service_port: "{{ myapp_port | default(80) }}"
    

    在这种情况下,当Ansible在某个表达式中碰到 apache_listen_port 时,它会将值模板化为 myapp_port 的值(如果在该特定时刻可用)或者否则使用 80 .

    如果在所需库存中定义 myapp_port ,则 apache_listen_portgreen_service_port 将获得其值 .

    如果您无法控制角色:

    你可以在剧本中制作这个技巧:

    vars:
      myapp_port_playbook: "{{ myapp_port | default(80) }}"
      apache_listen_port: "{{ myapp_port_playbook }}"
      green_service_port: "{{ myapp_port_playbook }}"
    

    在这种情况下, apache_listen_portgreen_service_port 直接模板化为 myapp_port_playbook 's value, but it'的值依次为 myapp_port 的值或 80 默认情况下 .

相关问题