Ansible 角色中的默认值和变量有什么区别?
Posted
技术标签:
【中文标题】Ansible 角色中的默认值和变量有什么区别?【英文标题】:What's the difference between defaults and vars in an Ansible role? 【发布时间】:2015-05-21 13:29:24 【问题描述】:在创建新的 Ansible 角色时,模板会同时创建一个 vars
和一个 defaults
目录以及一个空的 main.yml
文件。在定义我的角色时,我可以在其中任何一个中放置变量定义,它们将在我的任务中可用。
将定义放入defaults
和vars
有什么区别?什么应该进入defaults
,什么应该进入vars
?将两者用于相同的数据是否有意义?
我知道两者之间的优先级/优先级有所不同,但我想了解应该去哪里。
假设我的角色将在目标系统上创建一个目录列表。我想提供一个要创建的默认目录列表,但希望允许用户在使用角色时覆盖它们。
这就是它的样子:
---
- directories:
- foo
- bar
- baz
我可以把它放在defaults/main.yml
或vars/main.yml
中,从执行的角度来看,它不会有任何区别 - 但它应该放在哪里?
【问题讨论】:
【参考方案1】:variable precedence 上的 Ansible 文档很好地总结了这一点:
如果在不同的地方定义了多个同名变量,则按一定的顺序获胜,即:
额外的变量(命令行中的-e)总是获胜 然后是清单中定义的连接变量(ansible_ssh_user 等) 然后是“几乎所有其他内容”(命令行开关、正在运行的变量、包含变量、角色变量等) 然后是库存中定义的其余变量 然后是关于系统的事实发现 然后是“角色默认值”,这是最“默认”的,并且优先于所有内容。
因此,假设您有一个“tomcat”角色,用于在一堆 webhosts 上安装 Tomcat,但您需要在几个主机上使用不同版本的 tomcat,在其他情况下需要它以不同用户身份运行,等等。 defaults/main.yml
文件可能看起来像这样:
tomcat_version: 7.0.56
tomcat_user: tomcat
由于这些只是默认值,这意味着如果这些变量没有在其他任何地方为相关主机定义,它们将被使用。您可以通过额外变量、库存文件中的事实等覆盖这些变量,为这些变量指定不同的值。
编辑:请注意,以上列表适用于 Ansible 1.x。在 Ansible 2.x 中,该列表已被扩展。与往常一样,Ansible Documentation 提供了 2.x 变量优先级的详细说明。
【讨论】:
谢谢,这是一个很棒的页面——这就是我想要的。我更详细地介绍了defaults
中的内容以及vars
中的内容。
值得强调:角色变量具有邪恶高优先级。根据我的经验,它们比 play vars 更高,这真的很烦人。
5 年后,但是......我倾向于这样看待它:角色默认值是我希望角色用户在他们的某个地方覆盖的东西。角色变量 OTOH 允许我避免在任务中硬编码信息,但可能只会被覆盖以进行测试,并由角色维护者更改。例如,初始管理员用户名将在默认值中,但依赖版本将在 vars 中。【参考方案2】:
var
中定义的角色变量具有非常高的优先级 - 它们只能通过在命令行、特定任务或块中传递它们来覆盖。因此,几乎所有的变量都应该在defaults
中定义。
在“Variable Precedence - Where To Put Your Role Vars”一文中,作者给出了一个示例来说明在vars
中添加的内容:变化不大的系统特定常量。因此,您可以让 vars/debian.yml
和 vars/centos.yml
具有相同的变量名称但不同的值,并有条件地包含它们。
【讨论】:
【参考方案3】:恕我直言,Ansible 在 roles 的 vars 中设置如此高的优先级是不切实际且不明智的。 vars/main.yml
和 defaults/main.yml
中的配置应该很低,并且可能具有相同的优先级。
是否存在我们想要这种行为的真实案例?
有些例子我们不想要。
这里要说明的是defaults/main.yml
中的配置不能是动态的。配置在vars/main.yml
即可。因此,例如,您可以动态包含特定操作系统和版本的配置,如geerlingguy.postgresql中所示
但由于 Ansible 中的优先级是如此奇怪和不切实际,所以需要引入 伪变量,如 variables.yml
所示- name: Define postgresql_packages.
set_fact:
postgresql_packages: " __postgresql_packages | list "
when: postgresql_packages is not defined
这是一个具体的现实生活示例,表明优先级是不切实际的。
这里要说明的另一点是我们希望角色是可配置的。角色可以是外部的,由其他人管理。作为一般规则,您不希望角色中的配置具有高优先级。
【讨论】:
这应该是评论,而不是答案。【参考方案4】:基本上,“角色默认值”(角色内的默认文件夹)中的任何内容都是最具可塑性且最容易被覆盖的。角色的 vars 目录中的任何内容都会覆盖命名空间中该变量的先前版本。这里要遵循的想法是,范围越明确,命令行 -e extra vars 总是获胜的优先级就越高。主机和/或库存变量可以胜过角色默认值,但不能像 vars 目录或 include_vars 任务那样明确包含。 doc
【讨论】:
【参考方案5】:变量和默认值齐头并进。这是一个例子
-name: install package
yum: name=xyzpackage_version state=present
在你的默认文件中,你会有类似的东西:
package_version: 123
ansible 会做的是,它会获取 package_version
的值并将其放在包名称旁边,这样它就会在某处读取为:
-name: install package
yum: name=xyz123 state=present
这样它将安装xyz123
而不是xyz123.4
或xyz 的大存储库中的任何内容。
最后它会做yum install -y xyz123
所以基本上默认值是存在的值,如果您没有为变量设置特定值,则导致该空间不能保持为空。
【讨论】:
投反对票,因为它没有解决问题。显然,defaults
在没有定义 vars
时使用,但答案没有解释,为什么你会将一个值定义为一个或另一个,这是 OP 所要求的。比较下面的解释。以上是关于Ansible 角色中的默认值和变量有什么区别?的主要内容,如果未能解决你的问题,请参考以下文章