目录
[什么是 Ansible 事实?](#什么是 Ansible 事实?)
[在 Playbook 中使用事实](#在 Playbook 中使用事实)
[魔法变量(Magic Variables)](#魔法变量(Magic Variables))
前言:
在 Ansible 自动化运维中,了解受管主机的状态和配置是至关重要的。Ansible 事实(Facts)正是为此而生,它让您能够轻松获取和利用主机的各种信息,实现更智能、更自适应的自动化配置。
什么是 Ansible 事实?
Ansible 事实是 Ansible 在受管主机上自动检测到的变量。这些事实含有与主机相关的信息,可以像 play 中的常规变量、条件、循环或依赖于从受管主机收集的值的任何其他语句那样使用。
事实包含的信息类型
为受管主机收集的一些事实可能包括:
-
主机身份信息:主机名称、完全限定的域名
-
系统信息:内核版本、操作系统版本
-
硬件信息:CPU 数量、提供的或可用的内存
-
网络信息:网络接口名称、网络接口 IP 地址
-
存储信息:存储设备的大小和可用空间
事实的实际应用价值
借助事实,可以方便地检索受管主机的状态,并根据该状态确定要执行的操作。例如:
-
服务管理:您的 play 可能会通过使用基于所收集事实的值(如特定服务的状态)的条件任务来重新启动服务器。
-
配置优化:Play 可以根据事实报告的可用内存来自定义 MySQL 配置文件。
-
网络配置:可以根据事实的值设置配置文件中使用的 IPv4 地址。
事实收集机制
自动收集过程
通常,每个 play 在执行第一个任务之前会先自动运行 ansible.builtin.setup 模块来收集事实。这在 Ansible 2.3 或更高版本中报告为 Gathering Facts 任务,或者在更早的 Ansible 版本中报告为 setup 。默认情况下,您无需具有在 play 中运行 ansible.builtin.setup 的任务。它通常会自动为您运行。
查看收集到的事实
查看为受管主机收集的事实的一种方式是,运行一个收集事实并使用 ansible.builtin.debug 模块显示 ansible_facts 变量值的简短 playbook。
bash
- name: Fact dump
hosts: all
tasks:
- name: Print all facts
ansible.builtin.debug:
var: ansible_facts
运行该 playbook 时,事实将显示在作业输出中。Playbook 以 JSON 格式显示 ansible_facts 变量的内容,作为变量的字典。您可以浏览输出来查看收集了哪些事实,并查找您可能要在 play 中使用的事实。
常用事实示例
下表显示了可能从受管节点收集的、可以在 playbook 中使用的一些事实:
| 事实描述 | 变量 |
|---|---|
| 简短主机名称 | ansible_facts['hostname'] |
| 完全限定的域名 | ansible_facts['fqdn'] |
| 主要 IPv4 地址(基于路由) | ansible_facts['default_ipv4']['address'] |
| 所有网络接口的名称列表 | ansible_facts['interfaces'] |
/dev/vda1磁盘分区的大小 |
ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
| DNS 服务器列表 | ansible_facts['dns']['nameservers'] |
| 当前运行的内核的版本 | ansible_facts['kernel'] |
变量访问语法
请记住,当变量值为字典时,可使用两种语法中的一种来检索该值。从上表中举两个例子:
-
ansible_facts['default_ipv4']['address']也可以写成ansible_facts.default_ipv4.address -
ansible_facts['dns']['nameservers']也可以写成ansible_facts.dns.nameservers
在 Playbook 中使用事实
动态变量替换
在 playbook 中使用事实时,Ansible 将事实的变量名动态替换为对应的值:
bash
---
- hosts: all
tasks:
- name: Prints various Ansible facts
ansible.builtin.debug:
msg: >
The default IPv4 address of {{ ansible_facts.fqdn }}
is {{ ansible_facts.default_ipv4.address }}
下列输出演示了 Ansible 如何查询受管节点,并且动态使用系统信息来更新变量。您也可使用事实来创建符合特定条件的动态主机组。
事实的命名系统演进
新旧命名系统对比
在 Ansible 2.5 之前,事实总是作为以 ansible_ 字符串为前缀的单个变量注入,而不是作为 ansible_facts 变量的一部分。例如,ansible_facts['distribution'] 事实称为 ansible_distribution。
许多 playbook 使用的仍然是作为变量注入的事实,而非使用 ansible_facts.* 命名空间的新语法。
Ansible 社区不鼓励将事实作为变量注入的一个原因在于这可能会导致事实与变量之间出现意外冲突。事实具有非常高的优先级,会覆盖 playbook 和清单主机及组变量,因此这可能会造成意外的副作用。
新旧名称对比示例
下表显示了一些同时具有 ansible_* 和 ansible_facts.* 名称的事实示例:
| ansible_facts name* | ansible_ name* |
|---|---|
ansible_facts['hostname'] |
ansible_hostname |
ansible_facts['fqdn'] |
ansible_fqdn |
ansible_facts['default_ipv4']['address'] |
ansible_default_ipv4['address'] |
ansible_facts['interfaces'] |
ansible_interfaces |
ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
ansible_devices['vda']['partitions']['vda1']['size'] |
ansible_facts['dns']['nameservers'] |
ansible_dns['nameservers'] |
ansible_facts['kernel'] |
ansible_kernel |
配置事实命名系统
重要提示 :目前,Ansible 既能识别新的事实命名系统(使用 ansible_facts),也能识别 2.5 版之前的"作为单独变量注入事实"的更早命名系统。
您可通过将 Ansible 配置文件 [defaults] 部分中的 inject_facts_as_vars 参数设置为 false 来禁用 ansible_ * 命名系统。默认设置目前为 true。
如果设置为 false ,则只能使用新的 ansible_facts. * 命名系统引用 Ansible 事实。这种情况下,尝试通过 ansible_* 命名空间引用事实会导致错误。
控制事实收集
关闭事实收集
有时,您不想为 play 收集事实。造成这种情况的原因可能有很多:
-
性能考虑:您可能没有使用任何事实,并且希望加快 play 速度或减小 play 在受管主机上造成的负载。
-
环境限制 :受管主机可能因为某种原因而无法运行
ansible.builtin.setup模块,或者需要安装一些必备软件后再收集事实。
要为 play 禁用事实收集,可将 gather_facts 关键字设置为 no:
bash
yaml
- name: This play does not automatically gather any facts
hosts: large_datacenter
gather_facts: no
即使为 play 设置了 gather_facts: no,您也可以随时通过运行使用 ansible.builtin.setup 模块的任务来手动收集事实。
收集事实的子集
默认会收集所有事实。您可以将 ansible.builtin.setup 模块配置为仅收集事实的子集,而非所有事实。例如,要仅收集硬件事实,请将 gather_subset 设置为 hardware:
bash
- name: Collect only hardware facts
ansible.builtin.setup:
gather_subset:
- hardware
如果要收集除特定子集以外的所有事实,请在子集名称前面添加一个感叹号 (!):
bash
- name: Collect all facts except for hardware facts
ansible.builtin.setup:
gather_subset:
- !hardware
创建和使用自定义事实
自定义事实的概念
您可以使用自定义事实来定义受管主机的特定值。Play 可以使用自定义事实来填充配置文件或按条件运行任务。
自定义事实在各受管主机的本地存储。这些事实整合到 ansible.builtin.setup 模块在受管主机上运行时收集的标准事实列表中。
您可在 INI 或 JSON 文件中静态定义自定义事实,也可以在运行 play 时动态生成自定义事实。动态自定义事实通过可执行脚本收集,这些脚本会生成 JSON 输出。
自定义事实的格式
以下示例静态自定义事实文件以 INI 格式编写。INI 格式的自定义事实文件包含由一个部分定义的顶层值,后跟用于待定义的事实的键值对:
bash
[packages]
web_package = httpd
db_package = mariadb-server
[users]
user1 = joe
user2 = jane
同样的事实也能以 JSON 格式提供。以下 JSON 事实等同于以上示例中 INI 格式指定的事实。JSON 数据可以存储在静态文本文件中,或者通过可执行脚本输出到标准输出:
bash
{
"packages": {
"web_package": "httpd",
"db_package": "mariadb-server"
},
"users": {
"user1": "joe",
"user2": "jane"
}
}
注意:自定义事实文件不能采用 playbook 那样的 YAML 格式。JSON 格式是最为接近的等效格式。
访问自定义事实
ansible.builtin.setup 模块会在 ansible_facts['ansible_local'] 变量中存储自定义事实。事实按照其定义文件名排列。例如,假设受管主机上的 /etc/ansible/facts.d/custom.fact 文件会生成前面的自定义事实。在这种情况下,ansible_facts['ansible_local']['custom']['users']['user1'] 的值为 joe。
您可通过与以下示例相似的 play 收集事实并使用 ansible.builtin.debug 模块显示 ansible_local 变量的内容,以检查自定义事实的结构:
bash
- name: Custom fact testing
hosts: demo1.example.com
gather_facts: yes
tasks:
- name: Display all facts in ansible_local
ansible.builtin.debug:
var: ansible_local
运行 play 时,您可能会看到类似以下示例的输出:
bash
...output omitted...
TASK [Display all facts in ansible_local] *******************************
ok: [demo1.example.com] => {
"ansible_local": {
"custom": {
"packages": {
"db_package": "mariadb-server",
"web_package": "httpd"
},
"users": {
"user1": "joe",
"user2": "jane"
}
}
}
}
...output omitted...
自定义事实的使用方式与 playbook 中的默认事实相同,可以通过 ansible_local 命名空间访问。
魔法变量(Magic Variables)
魔法变量简介
Ansible 会自动设置一些特殊变量,这些魔法变量也可用于获取与特定受管主机相关的信息。魔法变量的名称保留,因此您不应使用这些名称来定义变量。
四个最有用的魔法变量
四个最有用的魔法变量分别为:
-
hostvars:包含受管主机的变量,可以用于获取另一台受管主机的变量的值。如果还没有为受管主机收集事实,则它不会包含该主机的事实。 -
group_names:列出当前受管主机所属的所有组。 -
groups:列出清单中的所有组和主机。 -
inventory_hostname:包含清单中配置的当前受管主机主机名称。这可能因为各种原因而与事实报告的主机名称不同。
使用魔法变量示例
若要深入了解它们的值,一个途径是使用 ansible.builtin.debug 模块显示这些变量的值。
例如,下面的任务会使运行 play 的每台主机打印出 demo2.example.com 主机上所有网络接口的列表。只要事实是早期在 play 中或由 playbook 中的前一个 play 为 demo2 收集的,这项任务就有效。该任务会使用 hostvars 魔法变量来访问该主机的 ansible_facts['interfaces'] 事实。
bash
- name: Print list of network interfaces for demo2
ansible.builtin.debug:
var: hostvars['demo2.example.com']['ansible_facts']['interfaces']
您可以对常规变量使用同样的方法,而不仅仅是事实。请记住,前面的任务是由 play 中的每台主机运行的,因此更高效的做法是使用不同的模块将收集自一台主机的信息应用于其他每台受管主机的配置。
请记住,您可以在任务中使用 ansible.builtin.setup 模块随时刷新所收集的事实。但是,收集事实确实会延长 playbook 的运行时间。
还有几个其他魔法变量可用。有关更多信息,请参见 Ansible 官方文档。
注:魔法变量和事实都是 Ansible 在执行时自动完成和提供的
总结
Ansible 事实是自动化运维中的强大工具,它们提供了对受管主机状态的深入了解,使 playbook 能够根据实际环境做出智能决策。通过理解和使用事实、自定义事实以及魔法变量,您可以创建更加灵活、自适应和强大的自动化解决方案。