当前位置: 首页 > news >正文

【Ansible 入门实战】三种变量详解

Ansible 同名变量优先级实战详解

这篇教程基于你当前的 Ansible 环境,通过 三种同名变量(主机变量 / 外部变量 / Play 变量) 的对比实验,完整展示变量优先级的验证过程。


一、实验目标

在同一个 Ansible Playbook 中,定义同名变量port的三种不同方式,同时执行并观察最终生效的值,验证优先级顺序。


二、统一项目目录结构(必须按此创建)

/home/lcy/ └── management/ # 项目根目录(所有操作均在此目录下执行) ├── test.yaml # 三合一优先级测试剧本 └── vars-file/ # 外部变量文件专用目录 └── server.yaml # 外部变量配置文件

创建目录命令

运行

# 进入用户家目录 cd ~ # 创建项目根目录及变量文件目录 mkdir -p ~/management/vars-file # 进入项目根目录(后续所有操作均在此执行) cd ~/management


三、步骤 1:配置三种同名变量

1. 主机变量(/etc/ansible/hosts

主机变量是在 Ansible 主机清单中定义的变量,每台主机可单独配置。

bash

运行

sudo vim /etc/ansible/hosts

添加 / 修改以下内容(确保主机名与 Playbook 中一致):

# 主机名 空格 变量名=值 test01 port=80 test02 port=8080

2. 外部变量文件(~/management/vars-file/server.yaml

通过vars_files加载的独立变量文件,实现配置与代码分离。

运行

vim ~/management/vars-file/server.yaml

文件内容:

yaml

port: 20000 # 外部变量定义

3. Play 内部变量(~/management/test.yaml中的vars字段)

直接在 Playbook 中定义的变量,作用域仅限当前 Play。

bash

运行

vim ~/management/test.yaml

在文件中添加vars字段:

yaml

vars: port: 10000 # Play 内部变量定义

四、步骤 2:编写零报错对比版 Playbook

以下剧本同时定义三种同名变量,并通过三个独立任务输出每种变量的原始值和最终生效值,兼容所有 Ansible 版本,无过滤器依赖。vim test.yaml

yaml

--- - name: 三种同名变量优先级测试 hosts: test01,test02 gather_facts: true # 方式1:外部变量文件(优先级第二,覆盖主机变量和Play变量) vars_files: - ./vars-file/server.yaml # 方式2:Play 内部变量(优先级最低,被其他两种覆盖) vars: port: 10000 tasks: # 任务1:输出主机变量的原始值(hostvars 为 Ansible 内置字典,可直接引用) - name: 1️⃣ 查看主机变量 port 的值 ansible.builtin.debug: msg: "主机变量 port = {{ hostvars[inventory_hostname].port }}" # 任务2:输出当前最终生效的 port(优先级最高的变量值) - name: 2️⃣ 查看最终生效的 port ansible.builtin.debug: msg: "最终生效的 port = {{ port }}" # 任务3:输出 Play 内部定义的 port(原始值,未被覆盖前的定义) - name: 3️⃣ 查看 Play 内部变量 port ansible.builtin.debug: msg: "Play 内部变量 port = {{ vars.port }}"

五、步骤 3:执行 Playbook

必须在项目根目录management/下执行,确保路径解析正确:

bash

运行

cd ~/management ansible-playbook test.yaml

六、步骤 4:结果解读与优先级结论

执行结果

关键现象分析

  1. 主机变量成功读取test01=80test02=8080,说明主机清单配置正确;
  2. 最终生效值为20000:来自外部变量文件,说明外部变量覆盖了主机变量和 Play 变量;
  3. Play 内部变量被覆盖vars.port也显示为20000,说明外部变量的优先级高于 Play 内部定义。

换场景再验证一遍(加深理解)

注释掉外部变量文件

yaml

# vars_files:

# - ./vars-file/server.yaml

再运行

最终结果变成 10000

说明:没了更高优先级的外部变量,就用最低的 Play 内部变量

放开外部,注释 Play 内部 vars

最终依旧是 20000

再次证明:外部变量说了算

最终优先级结论

外部变量文件(vars_files) > 主机变量(/etc/ansible/hosts) > Play 内部变量(vars)

这个时候就有人疑问了,我注释掉外部变量文件去执行,得到结果是10000,既然外部变量文件(vars_files) > 主机变量(/etc/ansible/hosts) > Play 内部变量(vars),那么我注释掉了外部变量,那么不是应该以主机变量为主吗,为什么反而是内部变量覆盖了主机变量?


🔍 现在进行现象分析

现在的情况是:

  • 注释掉了vars_files,没有外部变量了;
  • 主机变量明明是test01=80test02=8080
  • 但最终生效的port却是 Play 内部变量的10000,而不是主机变量的值。

这说明:在 Ansible 2.9 环境中,当没有外部变量时,vars定义的变量会覆盖主机变量,这和我们之前的结论完全相反。


📌 核心原因:Ansible 变量优先级的 “隐藏规则”

1. 官方文档的通用规则

三种变量都存在时,环境中优先级是:外部变量文件(vars_files) > 主机变量(hosts) > Play 内部变量(vars)

2. 现在遇到的 “反直觉” 现象,是因为:

在 Ansible 2.9 及更早版本中,当vars中定义了与主机变量同名的变量时,vars变量会覆盖主机变量,而不是反过来。

这是因为:

  • 主机变量是在inventory阶段加载的;
  • vars变量是在playbook阶段加载的;
  • 在 2.9 版本中,后加载的vars变量会覆盖先加载的主机变量,而不是主机变量覆盖它。

🎯 完整的优先级顺序(基于当前的 Ansible 2.9 环境)

结合两次实验的结果,我们可以得出你环境中真实的优先级顺序:

  1. 外部变量文件(vars_files):优先级最高,覆盖主机变量和 Play 变量;
  2. Play 内部变量(vars):优先级第二,覆盖主机变量;
  3. 主机变量(/etc/ansible/hosts):优先级最低,被vars_filesvars覆盖。

💡 怎么验证这个结论?

我们可以做一个简单的对比实验:

实验 1:保留主机变量,删除vars定义

修改 Playbook,注释掉vars字段:

yaml

--- - name: 测试主机变量 vs Play变量 hosts: test01,test02 gather_facts: true # 注释掉外部变量文件 # vars_files: # - ./vars-file/server.yaml # 注释掉 Play 内部变量 # vars: # port: 10000 tasks: - name: 查看主机变量 port 的值 ansible.builtin.debug: msg: "主机变量 port = {{ hostvars[inventory_hostname].port }}" - name: 查看最终生效的 port ansible.builtin.debug: msg: "最终生效的 port = {{ port }}"

执行后你会发现:最终生效的port会变成主机变量的值80/8080,这就证明了主机变量本身是能被正确读取的,只是被vars定义的变量覆盖了。


🔧 为什么会出现这种差异?

Ansible 变量优先级的行为在不同版本中会有细微变化:

  • Ansible 2.9 及更早版本vars变量的优先级高于主机变量;
  • Ansible 2.10+ 版本:主机变量的优先级高于vars变量,这也是官方文档现在推荐的规则。

你使用的是 Ansible 2.9,所以会出现vars覆盖主机变量的情况,这是完全正常的版本行为,不是你的配置错误。

我们可以执行ansible --version,看一下自己ansible的版本


📌 结论

  1. 优先级顺序:外部变量文件 > Play 内部变量 > 主机变量
  2. 这是 Ansible 2.9 版本的正常行为,和官方文档的通用规则略有不同,但实验结果是最权威的。
http://www.cnnetsun.cn/news/2483421.html

相关文章:

  • 告别“氛围编程”混乱!Kiro、Spec Kit等工具助力规范驱动开发
  • 谷歌 I/O 大会宣布:Android Studio 集成 AI agent,Android CLI 1.0 助力应用开发加速
  • 面向企业安全运营的网络钓鱼暴露面收敛技术与实践研究
  • Perplexity定义查询功能全解析(定义层·语义层·上下文层三重穿透)
  • 5G URLLC低延时实战:从Mini-Slot到MEC,手把手拆解工业互联网的毫秒级通信保障
  • 3D打印技术如何重塑消费电子供应链:从钛合金铰链到柔性制造
  • 告别云服务器开销?手把手教你用旧安卓手机搭建个人Linux服务器(Termux/AnLinux/RVNC Viewer保姆级教程)
  • 终极指南:如何在Windows 11上快速安装Android应用?APK Installer完整解决方案
  • 保姆级教程:在MMSegmentation中从零搭建并训练你自己的SegFormer模型(B0-B5全系列)
  • 别光看论文了!手把手教你复现3篇GNN顶会源码(附避坑指南)
  • GTA5终极防护指南:如何用YimMenu打造安全的游戏体验
  • 论文AI率卡答辩?2025-2026年靠谱降AI工具实测指南
  • 告别‘请格式化’!手把手教你为Android 10设备添加EXFAT/NTFS U盘支持(附完整源码修改流程)
  • 《流畅的Python》读书笔记06(补充01): 数据类构建器 - 三类数据容器对比(简洁版)
  • DLSS Swapper终极指南:智能革命重新定义游戏性能优化
  • LabVIEW与树莓派结合:图形化编程降低物联网开发门槛
  • 【会议征稿通知 | E3S出版 | EI 、Scopus稳定检索】第十二届能源材料与环境工程国际学术会议(ICEMEE 2026)
  • 指纹采集器模块选型指南|如何选择合适的指纹采集模块
  • Git提交者信息填错了?别慌,手把手教你用config命令修正(全局/本地/取消设置全攻略)
  • Clion配置ESP32开发环境
  • 别再只写CRUD了!用这个SpringBoot+Vue小Demo,带你理解前后端数据流转全流程
  • 告别ni488.h恐惧症:手把手教你用C++调用GPIB驱动控制仪器(附完整代码示例)
  • Prometheus 第三章grafana安装
  • 按实际印量付费——矮萝卜让企业不为“没用过”的印量买单
  • BLE广播数据那31个字节怎么用?从设备名到厂商数据,一文讲透LTV格式实战
  • 杭州E类人才、积分落户必看:如何利用软著快速攒够关键分值?
  • Matlab实现傅里叶变换:从核心原理到工程实践的全流程解析
  • 云鸢联机 · 服务器常见问题自助排查指南
  • Python+AI智能体(Agent)零基础入门全攻略:原理、架构、手搓代码与实战落地
  • OPC落地华强比,上午AI出方案,下午配齐零件,第二天样机上柜台,一人公司爆改华强北