Ansible 角色中的 defaults 和 vars 有什么区别?
What's the difference between defaults and vars in an Ansible role?
创建新的 Ansible 角色时,模板会创建一个 vars
和一个 defaults
目录,其中包含一个空 main.yml
文件。在定义我的角色时,我可以在其中任何一个中放置变量定义,它们将在我的任务中可用。
将定义放入defaults
和vars
有什么区别?什么应该进入 defaults
,什么应该进入 vars
?将两者用于相同的数据有意义吗?
我知道这两者在 precedence/priority 上有区别,但我想了解应该放在哪里。
假设我的角色将在目标系统上创建一个目录列表。我想提供要创建的默认目录列表,但希望允许用户在使用角色时覆盖它们。
这是它的样子:
---
- directories:
- foo
- bar
- baz
我可以将它放入 defaults/main.yml
或 vars/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.yml
和 vars/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 在 roles 的 vars 中将配置置于如此高的优先级是不切实际且不明智的。 vars/main.yml
和 defaults/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
创建新的 Ansible 角色时,模板会创建一个 vars
和一个 defaults
目录,其中包含一个空 main.yml
文件。在定义我的角色时,我可以在其中任何一个中放置变量定义,它们将在我的任务中可用。
将定义放入defaults
和vars
有什么区别?什么应该进入 defaults
,什么应该进入 vars
?将两者用于相同的数据有意义吗?
我知道这两者在 precedence/priority 上有区别,但我想了解应该放在哪里。
假设我的角色将在目标系统上创建一个目录列表。我想提供要创建的默认目录列表,但希望允许用户在使用角色时覆盖它们。
这是它的样子:
---
- directories:
- foo
- bar
- baz
我可以将它放入 defaults/main.yml
或 vars/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.yml
和 vars/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 在 roles 的 vars 中将配置置于如此高的优先级是不切实际且不明智的。 vars/main.yml
和 defaults/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