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 回答
请记住,在Ansible中,
{{ ... }}
表达式通常以惰性方式进行模板化(除了set_fact
),因此您不是"assign"变量,而是告诉Ansible如何在运行时获取该值 .如果您可以控制角色:
你可以
roles/apache/defaults/main.yml
:和
roles/green_service/defaults/main.yml
:在这种情况下,当Ansible在某个表达式中碰到
apache_listen_port
时,它会将值模板化为myapp_port
的值(如果在该特定时刻可用)或者否则使用80
.如果在所需库存中定义
myapp_port
,则apache_listen_port
和green_service_port
将获得其值 .如果您无法控制角色:
你可以在剧本中制作这个技巧:
在这种情况下,
apache_listen_port
和green_service_port
直接模板化为myapp_port_playbook
's value, but it'的值依次为myapp_port
的值或80
默认情况下 .