Ansible 角色中的 defaults 和 vars 有什么区别?

What's the difference between defaults and vars in an Ansible role?

创建新的 Ansible 角色时,模板会创建一个 vars 和一个 defaults 目录,其中包含一个空 main.yml 文件。在定义我的角色时,我可以在其中任何一个中放置变量定义,它们将在我的任务中可用。

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

我知道这两者在 precedence/priority 上有区别,但我想了解应该放在哪里。

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

这是它的样子:

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

我可以将它放入 defaults/main.ymlvars/main.yml,从执行的角度来看,它不会有任何区别 - 但它应该放在哪里?

variable precedence 上的 Ansible 文档很好地总结了这一点:

If multiple variables of the same name are defined in different places, they win in a certain order, which is:

  • extra vars (-e in the command line) always win
  • then comes connection variables defined in inventory (ansible_ssh_user, etc)
  • then comes "most everything else" (command line switches, vars in play, included vars, role vars, etc)
  • then comes the rest of the variables defined in inventory
  • then comes facts discovered about a system
  • then "role defaults", which are the most "defaulty" and lose in priority to everything.

所以假设你有一个“tomcat”角色,你用来在一堆网络主机上安装 Tomcat,但是你需要在几个主机上安装不同版本的 tomcat,在其他情况下需要它 运行 作为不同的用户,等等。 defaults/main.yml 文件可能看起来像这样:

tomcat_version: 7.0.56
tomcat_user: tomcat

因为这些只是默认值,这意味着如果这些变量没有在其他任何地方为相关主机定义,它们将被使用。您可以通过额外变量、清单文件中的事实等来覆盖这些变量,从而为这些变量指定不同的值。

编辑:请注意,上面的列表是针对 Ansible 1.x 的。在 Ansible 2.x 中,该列表已经扩展。一如既往,Ansible Documentation 提供了对 2.x.

变量优先级的详细描述

var 中定义的角色变量具有非常高的优先级 - 它们只能通过在命令行、特定任务或块中传递它们来覆盖。因此,几乎所有的变量都应该在 defaults.

中定义

在“Variable Precedence - Where To Put Your Role Vars”一文中,作者给出了一个例子,说明在 vars 中放入的内容:System-specific 变化不大的常量。因此,您可以让 vars/debian.ymlvars/centos.yml 具有相同的变量名但不同的值,并有条件地包含它们。

变量和默认值齐头并进。这是一个例子

-name: install package
 yum: name=xyz{{package_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

所以基本上默认值是存在的值,如果您没有为变量设置特定值,导致 space 不能留空。

恕我直言,Ansible 在 rolesvars 中将配置置于如此高的优先级是不切实际且不明智的。 vars/main.ymldefaults/main.yml 中的配置应该很低,并且可能具有相同的优先级。

现实生活中有没有我们想要这种行为的案例?

有些例子我们不想要这个。

这里要说明的是 defaults/main.yml 中的配置不能是动态的。配置在vars/main.yml即可。因此,例如,您可以动态包含特定 OS 和版本的配置,如 geerlingguy.postgresql

所示

但是因为 Ansible 中的优先级是如此奇怪和不切实际,geerlingguy 需要引入 伪变量,如 variables.yml

中所示
- name: Define postgresql_packages.
  set_fact:
    postgresql_packages: "{{ __postgresql_packages | list }}"
  when: postgresql_packages is not defined

这是一个具体的现实生活示例,表明优先级是不切实际的。

这里要说明的另一点是我们希望角色是可配置的。角色可以是外部的,由其他人管理。作为一般规则,您不希望角色中的配置具有高优先级。

基本上,进入“角色默认值”(角色内的默认文件夹)的任何内容都是最可塑且最容易覆盖的。角色的 vars 目录中的任何内容都会覆盖命名空间中该变量的先前版本。这里要遵循的想法是,您在范围内越明确,命令行的优先级就越高 -e extra vars 总是获胜。主机 and/or 清单变量可以赢得角色默认值,但不能像 vars 目录或 include_vars 任务那样显式包含。 doc