控制 Ansible 行为:优先级规则

为了让你在管理环境时拥有最大的灵活性,Ansible 提供了许多方法来控制 Ansible 的行为:它如何连接到被管理节点,以及它连接后如何工作。如果你使用 Ansible 来管理大量服务器、网络设备和云资源,你可能在几个不同的地方定义 Ansible 行为,并将这些信息以几种不同的方式传递给 Ansible。这种灵活性很方便,但如果你不了解优先级规则,它可能会适得其反。

这些优先级规则适用于可以在多种方式(通过配置设置、命令行选项、剧本关键字、变量)定义的任何设置。

优先级类别

Ansible 提供了四种控制其行为的来源。按优先级从最低(最容易被覆盖)到最高(覆盖所有其他优先级),这些类别是

  • 配置设置

  • 命令行选项

  • 剧本关键字

  • 变量

  • 直接赋值

每个类别都会覆盖所有低优先级类别的任何信息。例如,剧本关键字将覆盖任何配置设置。

在每个优先级类别中,都会应用特定的规则。但是,一般来说,‘最后定义’获胜,并覆盖任何以前的定义。

配置设置

配置设置 包括来自 ansible.cfg 文件和环境变量的值。在这个类别中,在配置文件中设置的值具有较低的优先级。Ansible 使用它找到的第一个 ansible.cfg 文件,忽略所有其他文件。Ansible 按以下顺序搜索这些位置的 ansible.cfg

  • ANSIBLE_CONFIG(如果设置了环境变量)

  • ansible.cfg(在当前目录中)

  • ~/.ansible.cfg(在主目录中)

  • /etc/ansible/ansible.cfg

环境变量比 ansible.cfg 中的条目具有更高的优先级。如果你在控制节点上设置了环境变量,它们会覆盖 Ansible 加载的任何 ansible.cfg 文件中的设置。任何给定环境变量的值都遵循正常的 shell 优先级:最后定义的值会覆盖以前的值。

命令行选项

任何命令行选项都会覆盖任何配置设置。

当你直接在命令行中键入某些内容时,你可能觉得你手工制作的值应该覆盖所有其他值,但 Ansible 并非如此。命令行选项具有较低的优先级 - 它们只覆盖配置。它们不会覆盖剧本关键字、来自库存的变量或来自剧本的变量。

你可以通过 在命令行中使用 -e 额外变量 来覆盖所有其他来源中的所有其他设置,但这不是命令行选项,而是一种传递 变量 的方式。

在命令行中,如果你为一个只接受单个值的参数传递多个值,那么最后定义的值将获胜。例如,此 临时任务 将以 carol 的身份连接,而不是 mike

ansible -u mike -m ping myhost -u carol

某些参数允许多个值。在这种情况下,Ansible 将追加来自库存文件 inventory1 和 inventory2 中列出的所有主机的所有值

ansible -i /path/inventory1 -i /path/inventory2 -m ping all

每个 命令行工具 的帮助都列出了该工具可用的选项。

剧本关键字

任何 剧本关键字 都将覆盖任何命令行选项和任何配置设置。

在剧本关键字中,优先级随着剧本本身而流动;越具体,对越一般的优先级越高

  • 剧本(最一般)

  • 块/包含/导入/角色(可选,可以包含任务,并且可以相互包含)

  • 任务(最具体)

一个简单的例子

- hosts: all
  connection: ssh
  tasks:
    - name: This task uses ssh.
      ping:

    - name: This task uses paramiko.
      connection: paramiko
      ping:

在这个例子中,connection 关键字在剧本级别设置为 ssh。第一个任务继承该值,并使用 ssh 连接。第二个任务继承该值,覆盖它,并使用 paramiko 连接。相同的逻辑也适用于块和角色。剧本中的所有任务、块和角色都继承剧本级别的关键字;任何任务、块或角色都可以通过在任务、块或角色中定义该关键字的不同值来覆盖任何关键字。

记住,这些是关键字,而不是变量。剧本和变量文件都是用 YAML 定义的,但它们具有不同的意义。剧本是 Ansible 的命令或‘状态描述’结构,变量是我们用来使剧本更动态的数据。

变量

Ansible 变量在优先级堆栈中非常高。它们会覆盖任何剧本关键字、任何命令行选项、环境变量和任何配置文件设置。

具有等效剧本关键字、命令行选项和配置设置的变量称为 连接变量。最初设计用于连接参数,此类别已扩展到包括其他核心变量,如临时目录和 Python 解释器。

连接变量(像所有变量一样)可以在多种方式和多个地方设置。你可以在 库存 中为主机和组定义变量。你可以在 剧本 中的 vars: 块中为任务和剧本定义变量。但是,它们仍然是变量 - 它们是数据,而不是关键字或配置设置。覆盖剧本关键字、命令行选项和配置设置的变量遵循与任何其他变量相同的 变量优先级 规则。

在剧本中设置时,变量遵循与剧本关键字相同的继承规则。你可以为剧本设置一个值,然后在任务、块或角色中覆盖它

- hosts: cloud
  gather_facts: false
  become: true
  vars:
    ansible_become_user: admin
  tasks:
    - name: This task uses admin as the become user.
      dnf:
        name: some-service
        state: latest
    - block:
        - name: This task uses service-admin as the become user.
          # a task to configure the new service
        - name: This task also uses service-admin as the become user, defined in the block.
          # second task to configure the service
      vars:
        ansible_become_user: service-admin
    - name: This task (outside of the block) uses admin as the become user again.
      service:
        name: some-service
        state: restarted

变量作用域:值可以存在多久?

在剧本中设置的变量值仅存在于定义它们的剧本对象中。这些‘剧本对象作用域’变量不可用于后续对象,包括其他剧本。

直接与主机或组关联的变量值,包括在库存中定义的变量、由 vars 插件定义的变量,或使用 set_factinclude_vars 等模块定义的变量,可用于所有剧本。这些‘主机作用域’变量也可以通过 hostvars[] 字典访问。

通过 extra vars 设置的变量对当前运行具有全局作用域,并且将作为‘剧本对象变量’和‘hostvars’ 存在。

在命令行中使用 -e 额外变量

要覆盖所有其他变量,你可以使用额外变量:--extra-vars-e 在命令行中。使用 -e 传递的值,虽然本身仍然是命令行选项,但它们在变量中具有最高的优先级,并且在大多数配置源中具有更高的优先级,这有点违反直觉,因为变量本身具有很高的优先级。例如,此任务将以 brian 的身份连接,而不是 carol

ansible -u carol -e 'ansible_user=brian' -a whoami all

你必须使用 --extra-vars 指定变量名和值。

直接赋值

此类别仅适用于接受直接选项的事物,通常是模块和某些插件类型。大多数模块和操作插件没有其他方法来分配设置,因此优先级很少在这种情况下出现,但对于其中一些插件来说,这仍然是可能的,并且应该反映在文档中。

- debug: msg='this is a direct assignment option to an action plugin'

- ping:
    data: also a direct assignment

除了任务操作之外,最容易识别的“直接赋值”是与查找、过滤和测试插件相关的。

lookup('plugin', direct1='value', direct2='value2')

'value_directly_assigned'|filter('another directly assigned')

'direct value' is testplugin

虽然大多数插件的配置方式都比较简单,特别是测试插件,但如果在插件或过滤器的文档中指定,它们也可以使用来自其他配置源的输入。

清单插件有点复杂,因为它们使用“清单源”,而这些源有时看起来像配置文件,并作为命令行选项传入,但这仍然被视为“直接赋值”。当使用内联源 -i host1, host2, host3 时,比使用文件源 -i /path/to/inventory_source 时更清晰,但它们的优先级相同。