跨清单使用变量与事实

AnsibleBeginner
立即练习

介绍

可复用的 playbook 应使用环境数据,而非硬编码开发和生产各自的答案。清单选择、变量作用域和目标事实决定每个节点收到什么内容。

你将使用两个分别选择不同 SSH 节点的清单,在各清单源旁存储组数据和主机数据,并通过一个 playbook 渲染设置。你还将应用临时额外变量覆盖,然后恢复稳定基线。

按环境分离清单数据

本步骤将为开发与生产提供独立的清单源及组变量值。

进入项目:

cd /home/labex/project

实验提供了两个小型清单。运行自动化前分别阅读它们:

cat inventories/dev/hosts.ini
cat inventories/prod/hosts.ini

dev 的 app 组包含 web1;prod 的 app 组包含 web2。地址和 SSH 设置已准备好。这些是真正不同的节点,而非 localhost 的两个名称。

-i 为本次调用选择清单源,覆盖项目默认清单。分别预览各环境:

ansible app -i inventories/dev/hosts.ini --list-hosts
ansible app -i inventories/prod/hosts.ini --list-hosts

预期 dev 为 web1,prod 为 web2。不要合并两个源来模拟隔离环境:源数据可能合并,相同清单主机名仍标识同一台主机。每个环境的调用都应保持明确。

变量是自动化使用的具名值。YAML 映射使用 name: value 行。Ansible 为清单中的 app 组加载清单旁的 group_vars/app.yml。请在各环境中为相同组名创建不同数据:

cat > inventories/dev/group_vars/app.yml <<'EOF'
environment_label: development
release_channel: preview
EOF
cat > inventories/prod/group_vars/app.yml <<'EOF'
environment_label: production
release_channel: stable
EOF

检查解析后的清单数据。--list 返回 JSON,其中包括存放主机值的 _meta.hostvars 对象:

ansible-inventory -i inventories/dev/hosts.ini --list
ansible-inventory -i inventories/prod/hosts.ini --list

dev 主机应解析为 development/preview;prod 主机为 production/stable。只有预期清单和组实际加载了变量文件,该文件才有作用。

使用主机变量与真实事实

本步骤将覆盖一台主机的组值,并将环境数据渲染为实际受管设置。

host_vars 下的文件以清单主机命名。对于同一主机和键,其主机变量覆盖此处使用的组变量。为开发环境的 Canary 提供主机特定发布通道:

cat > inventories/dev/host_vars/web1.yml <<'EOF'
release_channel: canary
EOF

开发环境的 environment_label 仍为 development,但 web1 的 release_channel 现在解析为 canary。生产环境仍为 stable。确认 dev 的解析结果:

ansible-inventory -i inventories/dev/hosts.ini --list

编写一个适用于任一清单的可复用 playbook:

cat > deploy-info.yml <<'EOF'
- name: Configure environment-specific application settings
  hosts: app
  gather_facts: true
  vars:
    banner_prefix: Managed environment
  tasks:
    - name: Write settings from variables and facts
      ansible.builtin.copy:
        dest: /home/automation/app-settings.conf
        content: |
          [application]
          environment={{ environment_label }}
          channel={{ release_channel }}
          host={{ inventory_hostname }}
          distribution={{ ansible_facts.distribution }}
          label={{ banner_prefix }}
        mode: "0640"
EOF

vars 定义 play 级别的值 banner_prefix。在 copy 内容中,{{ variable_name }} 在执行时插入值。这是基本的值替换;后续实验将管理独立的 Jinja 模板。

YAML 的 | 将后续缩进内容保留为多行文本,包括结尾换行。inventory_hostname 是当前清单名称。gather_facts 为 true 时,Ansible 在任务前收集目标数据;ansible_facts.distribution 提供实际操作系统发行版。它是目标数据,而非控制节点的事实。

检查语法,然后为各环境分别运行相同 playbook:

ansible-playbook -i inventories/dev/hosts.ini deploy-info.yml --syntax-check
ansible-playbook -i inventories/dev/hosts.ini deploy-info.yml
ansible-playbook -i inventories/prod/hosts.ini deploy-info.yml

通过各自清单读取两个实际文件:

ansible app -i inventories/dev/hosts.ini -m ansible.builtin.command -a 'cat /home/automation/app-settings.conf'
ansible app -i inventories/prod/hosts.ini -m ansible.builtin.command -a 'cat /home/automation/app-settings.conf'

开发环境应包含 environment=development、channel=canary 和 host=web1。生产环境应包含 environment=production、channel=stable 和 host=web2。两者都应包含 distribution=Ubuntu 和 label=Managed environment。共享 playbook 通过使用不同数据,生成了不同的目标内容。

覆盖单次调用并恢复基线

本步骤将使用额外变量而不编辑保存的清单数据,然后恢复到已收敛的基线。

-e 为本次执行提供额外变量。它覆盖此处演示的组值和主机值。仅在开发环境临时选择 hotfix 通道:

ansible-playbook -i inventories/dev/hosts.ini deploy-info.yml -e release_channel=hotfix

读取生成的 dev 配置:

ansible app -i inventories/dev/hosts.ini -m ansible.builtin.command -a 'cat /home/automation/app-settings.conf'

其 channel 应为 hotfix。-e 未编辑源 group_vars 和 host_vars 文件,也未选择生产环境。

不带额外变量运行,恢复 web1 保存的 canary 通道:

ansible-playbook -i inventories/dev/hosts.ini deploy-info.yml

现在预览两个基线环境:

ansible-playbook -i inventories/dev/hosts.ini deploy-info.yml --check
ansible-playbook -i inventories/prod/hosts.ini deploy-info.yml --check

每个选中主机应报告零项待应用更改,且无失败/不可达结果。这里练习的有限优先级关系是组数据、主机覆盖和额外变量覆盖。更复杂的优先级规则不属于本练习范围。

总结

你选择了不同环境的清单,加载组数据,应用主机特定覆盖,并用共享 playbook 渲染真实目标事实。临时额外变量更改了一次调用,后续基线运行使两个环境恢复到稳定的声明设置。