介绍
幂等性(Idempotence)意味着 Playbook 可以被重复执行,且仅在目标状态缺失或不一致时才会对系统进行更改。
在本实验中,你将使用常用的 Ansible 模块来创建目录和主机别名的配置文件,然后运行两次 Playbook,以证明第二次运行是稳定的。
创建幂等性练习项目
在此步骤中,你将创建一个包含两个本地受管主机别名的小型 Ansible 项目。每个别名都会写入其各自的目录,这样你既可以在单个 RHEL 10 虚拟机内操作,又能观察到针对不同主机的结果。
从默认的 LabEx 工作区开始。
cd /home/labex/project
-p 选项告诉 mkdir 在需要时创建父目录,并且如果目录已存在则直接成功。
mkdir -p rhce-ansible/{inventory/group_vars,playbooks,managed,reports}
cd rhce-ansible
创建项目默认配置,将 Ansible 指向你的清单文件并禁用重试文件(retry files)。
cat > ansible.cfg <<'EOF'
[defaults]
inventory = ./inventory/hosts
host_key_checking = False
retry_files_enabled = False
EOF
managed 目录将存放 Playbook 生成的文件,而 reports 将存放保存的 Playbook 输出。将它们分开存放可以更方便地对比预期内容与 Ansible 的运行记录。
定义本地受管主机和变量
在此步骤中,你将创建清单文件和组变量。这些别名使用 ansible_connection=local,这意味着 Ansible 在针对命名主机执行任务时,实际上是在当前虚拟机上安全地运行。
在执行此步骤的命令之前,请返回到 Ansible 项目目录。这样即使 LabEx 分步运行,命令也能保持稳定。
cd /home/labex/project/rhce-ansible
在同一个组中创建两个应用主机别名。
cat > inventory/hosts <<'EOF'
[app]
app1 ansible_connection=local
app2 ansible_connection=local
EOF
组变量描述了该组中所有主机共享的预期状态。
cat > inventory/group_vars/app.yml <<'EOF'
app_owner: labex
app_environment: training
app_message: Managed by Ansible common modules
EOF
确认 Ansible 可以识别这两个主机。
ansible app --list-hosts
输出应列出 app1 和 app2。在编写 Playbook 之前进行此检查非常有用,因为针对 app 组的 Play 只能影响清单中解析到该组的主机。
编写预期状态 Playbook
在此步骤中,你将编写一个使用 file、copy 和 lineinfile 的 Playbook。这些模块描述的是最终状态,而不是手动运行 shell 命令。
在执行此步骤的命令之前,请返回到 Ansible 项目目录。
cd /home/labex/project/rhce-ansible
创建 Playbook。路径中包含了 {{ inventory_hostname }},以便每个别名都能获得各自的输出目录。
cat > playbooks/common-modules.yml <<'EOF'
---
- name: Configure app host directories with common modules
hosts: app
gather_facts: false
tasks:
- name: Ensure host directory exists
ansible.builtin.file:
path: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}"
state: directory
mode: '0755'
- name: Install base application configuration
ansible.builtin.copy:
dest: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}/app.conf"
content: |
owner={{ app_owner }}
environment={{ app_environment }}
message={{ app_message }}
mode: '0644'
- name: Ensure managed message is present
ansible.builtin.lineinfile:
path: "/home/labex/project/rhce-ansible/managed/{{ inventory_hostname }}/app.conf"
line: "message={{ app_message }}"
create: true
mode: '0644'
EOF
file 任务用于创建目录,copy 任务用于写入完整的配置文件,而 lineinfile 任务展示了如何强制确保某一行内容存在。这些模块会将当前状态与预期状态进行比较,这就是它们能够实现幂等性的原因。
在运行新的 Playbook 之前,请先进行语法检查。
ansible-playbook playbooks/common-modules.yml --syntax-check
运行 Playbook 并检查文件
在此步骤中,你将首次运行预期状态 Playbook。由于目标文件尚不存在,第一次运行应该会报告更改。 在执行此步骤的命令之前,请返回到 Ansible 项目目录。
cd /home/labex/project/rhce-ansible
运行 Playbook 并保存输出以供后续对比。
ansible-playbook playbooks/common-modules.yml | tee reports/first-run.txt
第一次运行应该会报告更改,因为主机目录和 app.conf 文件都是新创建的。tee 命令让你可以在查看运行过程的同时,将输出保存下来用于幂等性检查。
检查 Ansible 创建的主机特定文件。
cat managed/app1/app.conf managed/app2/app.conf
两个文件应该包含相同的 owner、environment 和 message 值,但它们位于不同的主机别名目录下。这表明 Playbook 已将相同的预期状态应用到了每个清单主机上。
再次运行 Playbook 以验证幂等性
在此步骤中,你将再次运行同一个 Playbook。由于文件已经符合预期状态,Ansible 应该报告两个主机均无更改。 在执行此步骤的命令之前,请返回到 Ansible 项目目录。
cd /home/labex/project/rhce-ansible
第二次运行 Playbook 并保存输出。
ansible-playbook playbooks/common-modules.yml | tee reports/second-run.txt
在汇总行中查找 changed=0。
grep -E 'app[12].*changed=0' reports/second-run.txt
第二次运行出现 changed=0 是幂等性的关键信号。这意味着模块检查了现有文件,并发现无需进行任何修复。
总结
你构建了一个 Ansible 项目,使用常用模块描述了预期状态,运行了 Playbook,并通过第二次运行(报告无更改)验证了其幂等性。


