介绍
可复用的 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 渲染真实目标事实。临时额外变量更改了一次调用,后续基线运行使两个环境恢复到稳定的声明设置。


