Ansible:定义playbook"默认"对角色具有优先权但在库存中可覆盖的变量

时间:2018-03-14 15:44:23

标签: ansible ansible-2.x ansible-inventory

TL; DR

使用Ansible我试图在playbook级别定义某种默认变量 - 让我们称之为 playbook defaults - 它优先于其他角色默认但是可以通过库存 inventory group_vars / all 变量覆盖。

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

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

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

我希望实现的目标是:

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

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

  • "外部" components vars(来自Galaxy的角色)
  • "用途" vars(Playbook vars)
  • "环境"变种(开发,测试等)

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

使用简单应用程序的示例

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

  • 阿帕奇
  • 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个以上的环境服务时,它就变成了一场噩梦...更新一个简单的变量可能会对很多服务产生影响而且很难维护和理解。

公寓的答案"您的服务设计可能有误..." 我正在寻找避免这种情况的方法。

我想要实现的目标

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

# 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 个答案:

答案 0 :(得分:1)

请记住,在Ansible {{ ... }}中,表达式通常以惰性方式进行模板化(set_fact除外),因此您不能"分配"一个变量,但告诉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的值(如果在该特定时刻可用)或使用{{ 1}}否则。

如果您在必需的广告资源中定义80,则myapp_portapache_listen_port将获得其值。

如果您无法控制角色:

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

green_service_port
在这种情况下,

vars: myapp_port_playbook: "{{ myapp_port | default(80) }}" apache_listen_port: "{{ myapp_port_playbook }}" green_service_port: "{{ myapp_port_playbook }}" apache_listen_port会直接模仿green_service_port的值,但它的值依次为myapp_port_playbook&# 39; s值或默认为myapp_port