【问题标题】:How to configure attribute precedence to group_vars with Ansible如何使用 Ansible 为 group_vars 配置属性优先级
【发布时间】:2021-03-06 03:51:35
【问题描述】:

我的 Ansible 角色 vars/sonarqube.yml 有一个文件,其中包含内容

---
lvm_roles:
  sonarqube:
    size: '10g'
    path: '{{ sonar_home }}'

还有一个带有内容的文件group_vars/all/lvm.yml

lvm_roles:
  sonarqube:
    size: '20g'

ansible.cfg我有一条线

hash_behaviour = merge

没有merge,结果将是

lvm_roles:
  sonarqube:
    size: '20g'

换句话说,我失去了path var。

merge 的结果是

lvm_roles:
  sonarqube:
    size: '10g'
    path: '/opt/sonarqube'

然而我想要和期望的结果是

lvm_roles:
  sonarqube:
    size: '20g'
    path: '/opt/sonarqube'

所以期望的行为是

  1. Ansible 合并变量
  2. group_vars 中的配置优先于我的角色中的配置。

我可以在 Ansible 中配置此行为吗?如何?

【问题讨论】:

  • 我建议您阅读以下内容:the paragraph on vars precedenc in the doc。角色中的 /var 的优先级高于 group_vars。
  • 这很有趣。恕我直言,将这种优先级赋予 vars 目录中的 vars 是没有意义的。角色中的变量应该具有低优先级,因为您希望角色是可配置的。它没有意义很容易说明。你最终会得到像github.com/geerlingguy/ansible-role-postgresql/blob/master/vars/…中的“影子”变量@
  • 角色中的变量defaults 的优先级低于库存变量。角色中的变量 vars 的优先级高于库存变量。
  • @onknowns 正如 dgw 所指出的,您角色的可配置变量应该在 defaults/main.yml 中。如果你对这一切都不满意,ansible is opensource 这样你就可以轻松地提出问题,甚至提出 PR,看看他们是否愿意改变这一点(尽管我对此表示怀疑)。您关于 geerlingguys 角色的示例与您试图展示的完全相反:这些是您不希望任何人更改的内部变量。可定制的在github.com/geerlingguy/ansible-role-postgresql/blob/master/…
  • @Zeitounator 好的,为什么 geerlingguy 还要费心让这些变量可变呢?通过使用伪变量。这里的重点是人们想方设法改变 PostgreSQL 在偏离默认方式的系统上的安装方式。在我的站点上,我使用了一个以自定义方式安装 PostgreSQL 的内部托管服务提供商,而我可以使用 geerlingguy.postgresql 角色的唯一方法是因为 geerlingguy 不厌其烦地使用伪变量使这些变量可配置。 geerlingguy 使用伪变量降低了变量的优先级。

标签: ansible ansible-facts


【解决方案1】:

优先级在 Ansible 中是不可配置的,你不能给group_vars 中的配置比角色中vars 目录中的配置更高的优先级。

你想要的是 Ansible 不支持的 条件默认变量。例如此处Set Ansible role defaults conditionally 和此处use conditionals in vars ansible 所示。

这是 Ansible 作为 IaC 工具绝对缺乏的一个领域。例如,它是 Chef 中非常常用的功能。来自 Chef Apache 食谱的 attributes/default.rb 的片段演示了这种常见模式

....
case node['platform_family']
when 'rhel', 'fedora', 'amazon'
  if node['platform'] == 'amazon'
    default['apache']['package'] = 'httpd24'
    default['apache']['devel_package'] = 'httpd24-devel'
  else
    default['apache']['package'] = 'httpd'
    default['apache']['devel_package'] = 'httpd-devel'
  end
  default['apache']['service_name'] = 'httpd'
  default['apache']['perl_pkg']    = 'perl'
  default['apache']['apachectl']   = '/usr/sbin/apachectl'
  default['apache']['dir']         = '/etc/httpd'
  default['apache']['log_dir']     = '/var/log/httpd'

vars 目录中的配置可以与 Chef 中的“覆盖”属性进行比较。 Chef 食谱中的配置具有较低的优先级,但您可以使用“覆盖”属性来提供非常高的优先级。然而,在食谱中使用“覆盖”属性是非常少见的。它们的实际用途非常有限。反之亦然,Ansible vars 目录其预期用途创建覆盖几乎所有其他配置的高优先级配置,其实际用途非常有限。

如果您不同意,请分享我们绝对需要在角色中进行高优先级配置的角色示例。例如,您可以分享一个指向 Ansible 角色的链接,以演示实际用途。

vars 角色目录很有用,但不适用于其预期用途。在实践中,该目录用于存储条件配置。配置获得高优先级的事实比期望或预期的结果更成问题。

geerlingguy.posttgresql 角色证明了这一点。在这个角色中,geerlingguy 使用“伪变量”来解决 Ansible 没有条件默认变量的事实。

例如在vars/Debian-7.yml 中引入了一个变量__postgresql_data_dir。此变量获得高优先级。

__postgresql_data_dir: "/var/lib/postgresql/{{ __postgresql_version }}/main" 

除了可以用来模拟条件默认变量postgresql_data_dir,如tasks/variables.yml 中所示,它没有任何实际用途

- name: Define postgresql_data_dir.
  set_fact:
    postgresql_data_dir: "{{ __postgresql_data_dir }}"
  when: postgresql_data_dir is not defined

如果可以配置优先规则将是有意义的,因为 Ansible 角色中的 vars 目录通常由于其高优先级而具有有限的实际用途。要实际使用vars 目录,需要使用postgresql_data_dir 中的geerlingguy.posttgresql 角色来降低此目录中的配置优先级。

如果您不喜欢这种技巧,您也可以使用Set Ansible role defaults conditionally 中所述的解决方法set_factuse conditionals in vars ansible 中所述的邪恶内联编码。

建议 Ansible 社区将 vars 目录的预期用途从“覆盖”配置更改为“条件”配置。对角色中的配置给予高优先级是非常罕见的要求。然而,条件配置非常普遍。

【讨论】:

  • 这个角色表明你没有得到你一直在寻找的东西。但这并不能证明 Ansible 缺乏功能。相反,您可能想发布一个您认为无法在 Ansible 中解决的用例(包含所有详细信息)。
【解决方案2】:

问:"期望的行为是"

1) Ansible merges vars
2) config in group_vars takes precedence over config in my role.

我可以在 Ansible 中配置此行为吗?

答:不可以。precedence 无法更改。 “角色变量”(15) 覆盖 “group_vars”(7)。使用 "group_vars" 覆盖“角色默认值”(2)。

问:"你想要的是 Ansible 不支持的条件默认变量。"

答:如果 Ansible 不支持条件默认值,则无法为多个系统编写角色。可以创建条件默认值,例如

# Defaults variables
- name: "os_vars_playbook_dir: Vars from {{ playbook_dir }}/vars/defaults"
  include_vars: "{{ item }}"
  with_first_found:
    - files:
        - "{{ ansible_distribution }}-{{ ansible_distribution_release }}.yml"
        - "{{ ansible_distribution }}.yml"
        - "{{ ansible_os_family }}.yml"
        - "default.yml"
        - "defaults.yml"
      paths: "{{ playbook_dir }}/vars/defaults"
    
# Custom variables
- name: "os_vars_playbook_dir: Vars from {{ playbook_dir }}/vars"
  include_vars: "{{ item }}"
  with_first_found:
    - files:
        - "{{ ansible_distribution }}-{{ ansible_distribution_release }}.yml"
        - "{{ ansible_distribution }}.yml"
        - "{{ ansible_os_family }}.yml"
        - "default.yml"
        - "defaults.yml"
      paths: "{{ playbook_dir }}/vars"

(可在GitHub获得)


注意事项

  1. 在播放设置发现主机上正在运行的系统后,可以包含特定于操作系统的变量。

  2. 角色的 vars/defaults 具有非常高的优先级“include_vars”(18)(因为 1.)。但是这个目录应该只包含系统变量。在标准情况下,用户不想更改这些变量。

  3. 如有必要,可以在 vars/ 中自定义角色。 vars/ 中的自定义配置文件将在角色更新后继续存在,而 vars/defaults 可能会更新。

【讨论】:

  • 我的用例是有操作系统/发行版特定的变量,但有 host_vars/group_vars 优先。不知道该怎么做...即。以最小化缺失的功能来加载基于操作系统/发行版的默认值,例如。 defaults/main.yml,然后是defaults/{{ ansible_distribution }}.yml 等等...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 2022-06-18
  • 2021-08-08
  • 2015-06-15
相关资源
最近更新 更多