介绍
Ansible 是一个强大的 IT 自动化工具,可以帮助系统管理员和开发人员高效地管理基础设施。它的一个关键特性是能够收集关于目标系统的信息,这些信息被称为“facts”(事实)。Ansible 中的 gather_facts 选项决定了在 playbook 执行期间是否以及如何收集这些信息。
在这个实践实验(Lab)中,你将学习如何在 Ansible playbooks 中配置 gather_facts 选项。你将探索不同的设置,了解何时启用或禁用事实收集,并发现如何使用收集到的事实使你的 playbooks 更加动态和高效。通过完成这个实验,你将能够通过根据你的特定需求控制事实收集过程来优化你的 Ansible 工作流程。
安装 Ansible 并探索 gather_facts 选项
让我们从安装 Ansible 并探索 gather_facts 选项的作用开始。在这一步中,我们将安装 Ansible,创建一个简单的 inventory(清单),并运行一个命令来查看收集了哪些 facts(事实)。
安装 Ansible
首先,让我们在我们的系统上安装 Ansible:
sudo apt update
sudo apt install -y ansible
安装完成后,验证 Ansible 是否已正确安装:
ansible --version
你应该看到类似这样的输出:
ansible [core 2.12.x]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, Aug 14 2022, 00:00:00) [GCC 11.2.0]
jinja version = 3.0.3
libyaml = True
创建一个简单的 inventory(清单)
现在,让我们创建一个简单的 inventory 文件来使用。inventory 文件定义了 Ansible 将要管理的主机。对于这个实验,我们将创建一个本地 inventory:
mkdir -p ~/project/ansible
cd ~/project/ansible
使用编辑器创建一个名为 hosts 的 inventory 文件:
- 点击 WebIDE 中的 Explorer 图标
- 导航到
/home/labex/project/ansible目录 - 右键单击并选择“New File”(新建文件)
- 将文件命名为
hosts - 添加以下内容:
[local]
localhost ansible_connection=local
这个 inventory 设置了一个名为 local 的组,其中只有一个主机 - localhost。 ansible_connection=local 参数告诉 Ansible 直接在本地机器上执行命令,而无需使用 SSH。
探索 gather_facts
让我们运行一个简单的 Ansible 命令来查看默认情况下收集了哪些 facts(事实):
cd ~/project/ansible
ansible local -i hosts -m setup
上面的命令使用:
local:来自我们 inventory 的组-i hosts:指定我们的 inventory 文件-m setup:运行 setup 模块,该模块收集 facts(事实)
你将看到一个大型的 JSON 输出,其中包含有关你系统的详细信息,包括:
- 硬件信息(CPU,内存)
- 网络配置
- 操作系统详细信息
- 环境变量
- 等等
这些信息是 Ansible 在启用 gather_facts 时收集的(这是默认行为)。这些 facts(事实)可以在 playbooks 中使用,以便根据目标系统的特征做出决策或自定义任务。
创建一个具有默认事实收集的基本 playbook
在这一步中,我们将创建一个基本 Ansible playbook,它使用默认的事实收集行为并显示一些收集到的信息。
理解 Ansible playbooks
一个 Ansible playbook 是一个 YAML 文件,其中包含要在受管理主机上执行的任务列表。Playbooks 提供了一种以简单、人类可读的格式定义配置、部署和编排步骤的方法。
创建你的第一个 playbook
让我们创建一个简单的 playbook,它将显示 Ansible 默认收集的一些 facts(事实):
- 在 WebIDE 中,导航到
/home/labex/project/ansible目录 - 创建一个名为
facts_playbook.yml的新文件 - 添加以下内容:
---
- name: Show System Facts
hosts: local
## By default, gather_facts is set to 'true'
tasks:
- name: Display operating system
debug:
msg: "Operating System: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Display CPU information
debug:
msg: "CPU: {{ ansible_processor[1] }} with {{ ansible_processor_cores }} cores"
- name: Display memory information
debug:
msg: "Total Memory: {{ ansible_memtotal_mb }} MB"
- name: Display Python version
debug:
msg: "Python version: {{ ansible_python_version }}"
这个 playbook:
- 以我们在 inventory 中定义的
local组为目标 - 隐式地启用事实收集(默认行为)
- 包含四个任务,这些任务显示 Ansible 收集的不同信息
运行 playbook
现在让我们运行 playbook,看看收集到的 facts(事实)是如何运作的:
cd ~/project/ansible
ansible-playbook -i hosts facts_playbook.yml
你应该看到类似这样的输出:
PLAY [Show System Facts] *****************************************************
TASK [Gathering Facts] *******************************************************
ok: [localhost]
TASK [Display operating system] **********************************************
ok: [localhost] => {
"msg": "Operating System: Ubuntu 22.04"
}
TASK [Display CPU information] ***********************************************
ok: [localhost] => {
"msg": "CPU: Intel(R) Xeon(R) CPU with 2 cores"
}
TASK [Display memory information] ********************************************
ok: [localhost] => {
"msg": "Total Memory: 3907 MB"
}
TASK [Display Python version] ************************************************
ok: [localhost] => {
"msg": "Python version: 3.10.6"
}
PLAY RECAP *******************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
注意输出中的第一个任务:TASK [Gathering Facts]。这是 Ansible 在运行我们定义的任何任务之前自动收集 facts(事实),因为 gather_facts 的默认值为 true。
然后,playbook 成功地使用收集到的 facts(事实)显示了关于你系统的信息。每个 fact(事实)都使用带有 ansible_ 前缀的变量来引用。
禁用事实收集以提高性能
在这一步中,我们将学习如何禁用事实收集,以在不需要事实的情况下提高 playbook 的性能。
理解何时禁用事实收集
虽然收集事实很有用,但在某些情况下,它会增加不必要的开销:
- 当你运行不需要系统信息的简单任务时
- 当你经常执行 playbooks 并且事实没有改变时
- 当你想要优化 playbook 执行时间时
禁用事实收集可以显著提高 playbook 的执行速度,尤其是在管理多个主机时。
创建一个禁用事实收集的 playbook
让我们创建一个新的 playbook,它禁用了事实收集:
- 在 WebIDE 中,导航到
/home/labex/project/ansible目录 - 创建一个名为
no_facts_playbook.yml的新文件 - 添加以下内容:
---
- name: Playbook with Disabled Fact Gathering
hosts: local
gather_facts: false
tasks:
- name: Display current time
command: date
register: current_time
- name: Show the current time
debug:
msg: "Current time is: {{ current_time.stdout }}"
- name: List files in the project directory
command: ls -la ~/project
register: file_list
- name: Show file list
debug:
msg: "Project directory contents:\n{{ file_list.stdout }}"
这个 playbook:
- 使用
gather_facts: false显式地禁用事实收集 - 运行不依赖于系统事实的命令
- 使用
register关键字捕获命令输出 - 使用
debug模块显示捕获的信息
运行禁用事实收集的 playbook
让我们运行 playbook 并观察差异:
cd ~/project/ansible
ansible-playbook -i hosts no_facts_playbook.yml
你应该看到类似这样的输出:
PLAY [Playbook with Disabled Fact Gathering] *********************************
TASK [Display current time] **************************************************
changed: [localhost]
TASK [Show the current time] *************************************************
ok: [localhost] => {
"msg": "Current time is: Wed May 17 15:30:45 UTC 2023"
}
TASK [List files in the project directory] ***********************************
changed: [localhost]
TASK [Show file list] ********************************************************
ok: [localhost] => {
"msg": "Project directory contents:\ntotal 20\ndrwxr-xr-x 3 labex labex 4096 May 17 15:25 .\ndrwxr-xr-x 4 labex labex 4096 May 17 15:20 ..\ndrwxr-xr-x 2 labex labex 4096 May 17 15:25 ansible\n"
}
PLAY RECAP *******************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
注意,这次输出中没有 Gathering Facts 任务。Playbook 直接从我们定义的第一个任务开始。
比较执行时间
为了查看性能差异,让我们创建一个简单的计时脚本:
- 在 WebIDE 中,导航到
/home/labex/project/ansible目录 - 创建一个名为
compare_timing.sh的新文件 - 添加以下内容:
#!/bin/bash
echo "Running playbook with fact gathering enabled..."
time ansible-playbook -i hosts facts_playbook.yml > /dev/null
echo -e "\nRunning playbook with fact gathering disabled..."
time ansible-playbook -i hosts no_facts_playbook.yml > /dev/null
- 使脚本可执行:
chmod +x compare_timing.sh
- 运行比较脚本:
./compare_timing.sh
你应该看到输出显示禁用事实收集的 playbook 运行速度比启用事实收集的 playbook 快。在我们的简单示例中,差异可能很小,但在多个远程主机上运行复杂的 playbooks 时,差异可能很大。
使用选择性事实收集
在某些情况下,你可能只需要特定的 facts(事实),而不是所有系统信息。Ansible 允许选择性事实收集,以优化性能,同时仍然收集你需要的信息。
理解事实子集
Ansible 将 facts(事实)组织成子集,例如:
all:所有 facts(默认)min/minimal:一组最少的 factshardware:CPU、内存和设备信息network:网络接口和路由信息virtual:虚拟化详细信息ohai:来自 Ohai 的 facts(如果可用)facter:来自 Facter 的 facts(如果可用)
通过仅选择你需要的事实,你可以提高 playbook 的性能,同时仍然可以访问必要的信息。
创建一个具有选择性事实收集的 playbook
让我们创建一个 playbook,它仅收集与硬件相关的事实:
- 在 WebIDE 中,导航到
/home/labex/project/ansible目录 - 创建一个名为
selective_facts_playbook.yml的新文件 - 添加以下内容:
---
- name: Selective Fact Gathering
hosts: local
gather_facts: true
gather_subset:
- "!all" ## Exclude all facts by default
- "hardware" ## Then include only hardware facts
tasks:
- name: Display CPU information
debug:
msg: "CPU: {{ ansible_processor[1] }} with {{ ansible_processor_cores }} cores"
- name: Display memory information
debug:
msg: "Total Memory: {{ ansible_memtotal_mb }} MB"
- name: Try to access network facts (should fail)
debug:
msg: "Default IPv4 Address: {{ ansible_default_ipv4.address }}"
ignore_errors: true
这个 playbook:
- 使用
gather_facts: true启用事实收集 - 使用
gather_subset来限制收集哪些 facts(事实) - 首先使用
!all排除所有 facts - 然后仅使用
hardware包含硬件 facts - 尝试访问网络 facts(未收集),以演示此限制
运行具有选择性事实收集的 playbook
让我们运行 playbook,看看选择性事实收集是如何运作的:
cd ~/project/ansible
ansible-playbook -i hosts selective_facts_playbook.yml
你应该看到类似这样的输出:
PLAY [Selective Fact Gathering] **********************************************
TASK [Gathering Facts] *******************************************************
ok: [localhost]
TASK [Display CPU information] ***********************************************
ok: [localhost] => {
"msg": "CPU: Intel(R) Xeon(R) CPU with 2 cores"
}
TASK [Display memory information] ********************************************
ok: [localhost] => {
"msg": "Total Memory: 3907 MB"
}
TASK [Try to access network facts (should fail)] *****************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'address'..."}
...ignoring
PLAY RECAP *******************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
注意,前两个任务成功了,因为它们访问了已收集的硬件 facts,但第三个任务失败了,因为没有收集网络 facts。我们使用了 ignore_errors: true 来在发生此错误的情况下继续 playbook 的执行。
创建一个具有多个事实子集的 playbook
现在,让我们创建一个 playbook,它收集硬件和网络 facts:
- 在 WebIDE 中,创建一个名为
multiple_subsets_playbook.yml的新文件 - 添加以下内容:
---
- name: Multiple Fact Subsets
hosts: local
gather_facts: true
gather_subset:
- "!all" ## Exclude all facts by default
- "hardware" ## Include hardware facts
- "network" ## Include network facts
tasks:
- name: Display CPU information
debug:
msg: "CPU: {{ ansible_processor[1] }} with {{ ansible_processor_cores }} cores"
- name: Display memory information
debug:
msg: "Total Memory: {{ ansible_memtotal_mb }} MB"
- name: Display network information
debug:
msg: "Default IPv4 Address: {{ ansible_default_ipv4.address }}"
运行此 playbook:
ansible-playbook -i hosts multiple_subsets_playbook.yml
这次,所有任务都应该成功,因为我们已经收集了硬件和网络 facts。
在条件任务中使用已收集的事实
使用已收集的事实最强大的功能之一是在你的 playbooks 中实现条件逻辑。在这一步中,我们将创建一个 playbook,它使用 facts(事实)来决定运行哪些任务。
理解 Ansible 中的条件任务
Ansible 允许你使用 when 关键字,根据变量、facts(事实)或任务结果有条件地执行任务。这使你能够创建更具动态性和适应性的 playbooks。
创建一个具有条件任务的 playbook
让我们创建一个 playbook,它根据操作系统执行不同的操作:
- 在 WebIDE 中,导航到
/home/labex/project/ansible目录 - 创建一个名为
conditional_facts_playbook.yml的新文件 - 添加以下内容:
---
- name: Conditional Tasks Based on Facts
hosts: local
gather_facts: true
tasks:
- name: Display OS information
debug:
msg: "Running on {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Task for Ubuntu systems
debug:
msg: "This is an Ubuntu system. Would run apt commands here."
when: ansible_distribution == "Ubuntu"
- name: Task for CentOS systems
debug:
msg: "This is a CentOS system. Would run yum commands here."
when: ansible_distribution == "CentOS"
- name: Task for systems with at least 2GB RAM
debug:
msg: "This system has {{ ansible_memtotal_mb }} MB RAM, which is sufficient for our application."
when: ansible_memtotal_mb >= 2048
- name: Task for systems with less than 2GB RAM
debug:
msg: "This system has only {{ ansible_memtotal_mb }} MB RAM, which may not be sufficient."
when: ansible_memtotal_mb < 2048
这个 playbook:
- 收集有关系统的所有 facts(事实)
- 显示操作系统信息
- 根据操作系统类型有条件地执行任务
- 根据 RAM 的数量有条件地执行任务
运行条件 playbook
让我们运行 playbook,看看条件任务是如何运作的:
cd ~/project/ansible
ansible-playbook -i hosts conditional_facts_playbook.yml
由于我们正在 Ubuntu 上运行,你应该看到类似这样的输出:
PLAY [Conditional Tasks Based on Facts] **************************************
TASK [Gathering Facts] *******************************************************
ok: [localhost]
TASK [Display OS information] ************************************************
ok: [localhost] => {
"msg": "Running on Ubuntu 22.04"
}
TASK [Task for Ubuntu systems] ***********************************************
ok: [localhost] => {
"msg": "This is an Ubuntu system. Would run apt commands here."
}
TASK [Task for CentOS systems] ***********************************************
skipping: [localhost]
TASK [Task for systems with at least 2GB RAM] ********************************
ok: [localhost] => {
"msg": "This system has 3907 MB RAM, which is sufficient for our application."
}
TASK [Task for systems with less than 2GB RAM] *******************************
skipping: [localhost]
PLAY RECAP *******************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
注意,一些任务是如何执行的,而另一些任务是根据条件跳过的。CentOS 任务被跳过,因为我们正在 Ubuntu 上运行,并且“小于 2GB RAM”任务被跳过,因为我们的系统有超过 2GB RAM。
创建一个更实用的例子
现在,让我们创建一个更实用的例子,可以在真实环境中使用的例子:
- 在 WebIDE 中,创建一个名为
practical_conditional_playbook.yml的新文件 - 添加以下内容:
---
- name: Practical Conditional Playbook
hosts: local
gather_facts: true
vars:
app_dir: "/home/labex/project/app"
tasks:
- name: Create application directory
file:
path: "{{ app_dir }}"
state: directory
mode: "0755"
- name: Configure for production environment
copy:
dest: "{{ app_dir }}/config.yml"
content: |
environment: production
memory_limit: high
debug: false
when: ansible_memtotal_mb >= 4096
- name: Configure for development environment
copy:
dest: "{{ app_dir }}/config.yml"
content: |
environment: development
memory_limit: low
debug: true
when: ansible_memtotal_mb < 4096
- name: Display configuration
command: cat {{ app_dir }}/config.yml
register: config_content
- name: Show configuration
debug:
msg: "{{ config_content.stdout_lines }}"
这个 playbook:
- 为应用程序创建一个目录
- 根据可用的系统内存写入不同的配置文件
- 显示结果配置
运行实用的 playbook:
ansible-playbook -i hosts practical_conditional_playbook.yml
此示例演示了如何使用已收集的 facts(事实)根据系统特性自动调整配置。
总结
在这个实验中,你已经学会了如何在 Ansible playbooks 中有效地配置和使用 gather_facts 选项。以下是你已经完成的工作的总结:
基本事实收集:你已经安装了 Ansible,并探索了默认的事实收集行为,看到了 Ansible 收集的各种系统信息。
禁用事实收集:你已经学会了如何禁用事实收集,以在不需要 facts(事实)时提高 playbook 的性能。
选择性事实收集:你已经发现了如何仅收集特定子集的 facts(事实),以在性能和拥有必要信息之间取得平衡。
条件任务:你已经在你的 playbooks 中实现了基于已收集 facts(事实)的条件逻辑,从而允许根据系统特性进行动态行为。
实际应用:你已经创建了实际的例子,演示了如何在实际场景中使用已收集的 facts(事实)。
通过掌握 gather_facts 选项,你可以优化你的 Ansible playbooks,以获得更好的性能,同时仍然可以访问你需要的系统信息。这些知识将帮助你创建更有效、更灵活、更强大的自动化工作流程。
一些需要记住的最佳实践:
- 仅在必要时启用事实收集
- 当你只需要特定信息时,使用选择性事实收集
- 利用已收集的 facts(事实)进行条件任务,使你的 playbooks 更具适应性
- 考虑在同一主机上频繁运行 playbooks 时缓存 facts(事实)
有了这些技能,你已经为你的基础设施管理需求创建更复杂和更有效的 Ansible 自动化做好了充分准备。


