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 文件。在定义我的角色时,我可以在其中任何一个中放置变量定义,它们将在我的任务中可用。

将定义放入defaultsvars 有什么区别?什么应该进入defaults,什么应该进入vars?将两者用于相同的数据是否有意义?

我知道两者之间的优先级/优先级有所不同,但我想了解应该去哪里。

假设我的角色将在目标系统上创建一个目录列表。我想提供一个要创建的默认目录列表,但希望允许用户在使用角色时覆盖它们。

这就是它的样子:

---
- directories:
  - foo
  - bar
  - baz

我可以把它放在defaults/main.ymlvars/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.ymlvars/centos.yml 具有相同的变量名称但不同的值,并有条件地包含它们。

【讨论】:

【参考方案3】:

恕我直言,Ansible 在 rolesvars 中设置如此高的优先级是不切实际且不明智的。 vars/main.ymldefaults/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 角色中的默认值和变量有什​​么区别?的主要内容,如果未能解决你的问题,请参考以下文章

字段和变量有什​​么区别?

Docker和虚拟机有什什么区别?

将 Ansible 变量从一个角色(在一个主机上运行)传递给在同一剧本中的另一台主机上运行的另一个角色

Ansible 中的角色使用

java中变量被赋予空值和声明一个变量有何区别

,jenkins svn和jenkins svn ansible的区别在哪里?