控制 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
每个命令行工具的帮助列出了该工具的可用选项。
剧本关键字
任何剧本关键字都将覆盖任何命令行选项和任何配置设置。
在剧本关键字中,优先级随着剧本本身流动;越具体的值胜过越一般的值
play(最一般)
blocks/includes/imports/roles(可选,并且可以包含任务以及彼此包含)
tasks(最具体)
一个简单的示例
- hosts: all
connection: ssh
tasks:
- name: This task uses ssh.
ping:
- name: This task uses paramiko.
connection: paramiko
ping:
在此示例中,connection
关键字在 play 级别设置为 ssh
。第一个任务继承该值,并使用 ssh
连接。第二个任务继承该值,覆盖它,并使用 paramiko
连接。相同的逻辑也适用于 block 和 role。play 中的所有任务、block 和 role 都会继承 play 级别的关键字;任何任务、block 或 role 都可以通过在任务、block 或 role 中定义该关键字的不同值来覆盖任何关键字。
请记住,这些是关键字,而不是变量。剧本和变量文件都在 YAML 中定义,但它们具有不同的意义。剧本是 Ansible 的命令或“状态描述”结构,变量是我们用来帮助使剧本更动态的数据。
变量
Ansible 变量在优先级堆栈中非常高。它们将覆盖任何剧本关键字、任何命令行选项、环境变量和任何配置文件设置。
具有等效剧本关键字、命令行选项和配置设置的变量称为连接变量。最初是为连接参数设计的,该类别已扩展到包括其他核心变量,如临时目录和 Python 解释器。
连接变量(如所有变量)可以通过多种方式和位置进行设置。您可以在清单中定义主机和组的变量。您可以在剧本中的 vars:
代码块中定义任务和 play 的变量。但是,它们仍然是变量 - 它们是数据,而不是关键字或配置设置。覆盖剧本关键字、命令行选项和配置设置的变量遵循与任何其他变量相同的变量优先级规则。
在剧本中设置时,变量遵循与剧本关键字相同的继承规则。您可以为 play 设置一个值,然后在任务、block 或 role 中覆盖它
- 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
变量作用域:一个值可用多久?
在剧本中设置的变量值仅存在于定义它们的剧本对象中。这些“剧本对象作用域”变量对后续对象(包括其他 play)不可用。
直接与主机或组关联的变量值,包括在清单中、通过 vars 插件或使用诸如set_fact和include_vars之类的模块定义的变量,对所有 play 都可用。这些“主机作用域”变量也可以通过 hostvars[]
字典获得。
通过 extra vars
设置的变量在当前运行中具有全局作用域,并且将作为“剧本对象 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
时更清晰一些,但它们都具有相同的优先级。