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 port80 test02 port80802. 外部变量文件~/management/vars-file/server.yaml通过vars_files加载的独立变量文件实现配置与代码分离。运行vim ~/management/vars-file/server.yaml文件内容yamlport: 20000 # 外部变量定义3. Play 内部变量~/management/test.yaml中的vars字段直接在 Playbook 中定义的变量作用域仅限当前 Play。bash运行vim ~/management/test.yaml在文件中添加vars字段yamlvars: port: 10000 # Play 内部变量定义四、步骤 2编写零报错对比版 Playbook以下剧本同时定义三种同名变量并通过三个独立任务输出每种变量的原始值和最终生效值兼容所有 Ansible 版本无过滤器依赖。vim test.yamlyaml--- - name: 三种同名变量优先级测试 hosts: test01,test02 gather_facts: true # 方式1外部变量文件优先级第二覆盖主机变量和Play变量 vars_files: - ./vars-file/server.yaml # 方式2Play 内部变量优先级最低被其他两种覆盖 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结果解读与优先级结论执行结果关键现象分析主机变量成功读取test0180、test028080说明主机清单配置正确最终生效值为20000来自外部变量文件说明外部变量覆盖了主机变量和 Play 变量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没有外部变量了主机变量明明是test0180、test028080但最终生效的port却是 Play 内部变量的10000而不是主机变量的值。这说明在 Ansible 2.9 环境中当没有外部变量时vars定义的变量会覆盖主机变量这和我们之前的结论完全相反。 核心原因Ansible 变量优先级的 “隐藏规则”1. 官方文档的通用规则当三种变量都存在时环境中优先级是外部变量文件vars_files 主机变量hosts Play 内部变量vars2. 现在遇到的 “反直觉” 现象是因为在 Ansible 2.9 及更早版本中当vars中定义了与主机变量同名的变量时vars变量会覆盖主机变量而不是反过来。这是因为主机变量是在inventory阶段加载的vars变量是在playbook阶段加载的在 2.9 版本中后加载的vars变量会覆盖先加载的主机变量而不是主机变量覆盖它。 完整的优先级顺序基于当前的 Ansible 2.9 环境结合两次实验的结果我们可以得出你环境中真实的优先级顺序外部变量文件vars_files优先级最高覆盖主机变量和 Play 变量Play 内部变量vars优先级第二覆盖主机变量主机变量/etc/ansible/hosts优先级最低被vars_files和vars覆盖。 怎么验证这个结论我们可以做一个简单的对比实验实验 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的版本 结论优先级顺序外部变量文件 Play 内部变量 主机变量这是 Ansible 2.9 版本的正常行为和官方文档的通用规则略有不同但实验结果是最权威的。