Ansible 变量管理完全指南

一、概述

1. 简介

A. 是什么

Ansible 变量是 Playbook 中实现参数化配置的核心机制,通过变量可以实现同一套 Playbook 适配不同环境的配置需求。

B. 为什么学

  • 解决多环境配置复用问题,避免为 dev/test/prod 维护多份相似 Playbook
  • 理解变量优先级规则,避免同名变量导致的不可预测行为
  • 掌握变量工程化组织方法,让项目可维护、可扩展、可协作

C. 学完能做什么

  • 使用三种方式定义变量(Playbook vars / Inventory 组变量 / 命令行 -e)
  • 通过实验验证变量优先级,不再靠猜
  • 使用 vars_files 和 group_vars 实现工程化变量管理
  • 使用 register 捕获命令执行结果并在后续任务中使用
  • 按"环境差异/角色共性/主机个例"组织变量结构

2. 前置知识

A. 必备技能

  • 了解 Playbook 基本结构和语法
  • 掌握 Inventory 主机分组概念
  • 熟悉基本模块使用方法

B. 推荐知识

  • YAML 基础语法
  • Linux 命令行操作

二、实验环境

1. 系统要求

控制端:Rocky Linux 9.6,IP 192.168.10.10

受控端环境配置:

环境角色主机名IP
devwebdev-web1192.168.10.11
devwebdev-web2192.168.10.12
devdbdev-db1192.168.10.21
testwebtest-web1192.168.10.31
testdbtest-db1192.168.10.41
prodwebprod-web1192.168.10.51
prodwebprod-web2192.168.10.52
proddbprod-db1192.168.10.61

2. 环境准备

创建工作目录:

mkdir -p ~/ansible-07/{vars,group_vars}
cd ~/ansible-07

创建包含环境组和角色组的 Inventory:

cat > inventory <<'EOF'
[dev_web]
dev-web1 ansible_host=192.168.10.11
dev-web2 ansible_host=192.168.10.12

[dev_db]
dev-db1 ansible_host=192.168.10.21

[test_web]
test-web1 ansible_host=192.168.10.31

[test_db]
test-db1 ansible_host=192.168.10.41

[prod_web]
prod-web1 ansible_host=192.168.10.51
prod-web2 ansible_host=192.168.10.52

[prod_db]
prod-db1 ansible_host=192.168.10.61

[dev:children]
dev_web
dev_db

[test:children]
test_web
test_db

[prod:children]
prod_web
prod_db

[web:children]
dev_web
test_web
prod_web

[db:children]
dev_db
test_db
prod_db
EOF

验证连通性:

ansible all -i inventory -m ping

三、变量定义方式

1. 基本术语

  • vars:Playbook 内定义的变量
  • Inventory 组变量:在 Inventory 文件中为组定义的变量
  • 命令行变量:通过 -e 参数临时传入的变量
  • vars_files:独立变量文件
  • group_vars:按组自动加载的变量目录
  • register:注册变量,用于存储任务执行结果

2. 三种基础定义方式

A. Playbook 内定义变量(vars)

适用场景:演示、小实验、变量很少的情况

示例:vars_in_playbook.yml

- name: Vars in playbook demo
  hosts: dev_web
  vars:
    app_name: demoapp
    app_port: 8080
  tasks:
    - name: Show app config
      command: echo "app={{ app_name }} port={{ app_port }}"

执行:

ansible-playbook -i inventory vars_in_playbook.yml

B. Inventory 定义组变量

适用场景:多环境配置,工程中最常用

在 Inventory 末尾添加组变量:

cat >> inventory <<'EOF'

[dev:vars]
env=development
app_port=8080

[prod:vars]
env=production
app_port=80
EOF

示例:vars_from_inventory.yml

- name: Vars from inventory demo
  hosts: web
  tasks:
    - name: Show env and port
      command: echo "env={{ env }} port={{ app_port }}"

分别执行不同环境:

ansible-playbook -i inventory vars_from_inventory.yml -l dev
ansible-playbook -i inventory vars_from_inventory.yml -l prod

同一 Playbook 不改一行,输出随环境自动切换,这就是工程化"可复用"的关键能力。

C. 命令行传变量(-e)

适用场景:临时调试

ansible-playbook -i inventory vars_from_inventory.yml -l dev -e "app_port=9999"

注意:工程中大量依赖 -e 会导致"不可追溯",后期排错很痛苦。

3. 变量优先级规则

graph TD
    A[变量优先级] --> B[组变量<br/>Inventory / group_vars]
    A --> C[主机变量]
    A --> D[Playbook vars]
    A --> E[命令行 -e<br/>最高优先级]

    B --> F[优先级: 低]
    C --> G[优先级: 中低]
    D --> H[优先级: 中高]
    E --> I[优先级: 高]

    style F fill:#e1f5fe
    style G fill:#b3e5fc
    style H fill:#81d4fa
    style I fill:#4fc3f7

mermaid

变量优先级规则

A. 验证实验 1:Playbook vars 覆盖 Inventory 组变量

Inventory 中 dev 已有 app_port=8080,在 Playbook 中定义同名变量 app_port=1234:

cat > priority_test.yml <<'EOF'
- name: Priority test
  hosts: dev
  vars:
    app_port: 1234
  tasks:
    - name: Show app_port
      command: echo "app_port={{ app_port }}"
EOF

执行:

ansible-playbook -i inventory priority_test.yml

预期输出:app_port=1234,说明 Playbook vars 优先级高于 Inventory 组变量。

B. 验证实验 2:命令行 -e 覆盖一切

ansible-playbook -i inventory priority_test.yml -e "app_port=9999"

预期输出:app_port=9999,说明 -e 是最高优先级。

C. 记忆法

越临时的越优先。记忆顺序:组变量 < 主机变量 < Playbook vars < 命令行 -e

四、变量工程化三件套

1. 工程化演进路径

变量少:使用 vars
变量变多:使用 vars_files
真上项目:使用 group_vars

2. vars_files:变量文件化

创建变量文件 vars/app.yml:

cat > vars/app.yml <<'EOF'
app_name: demoapp
app_user: deploy
EOF

示例:vars_files_demo.yml

- name: vars_files demo
  hosts: dev_web
  vars_files:
    - vars/app.yml
  tasks:
    - name: Show app vars
      command: echo "name={{ app_name }} user={{ app_user }}"

适用场景:多个 Playbook 共享一份变量,但变量不随组/环境自动切换。

3. group_vars:按组自动加载

在 group_vars/ 目录下创建与组名同名的文件:

cat > group_vars/dev.yml <<'EOF'
env: development
app_port: 8080
EOF

cat > group_vars/prod.yml <<'EOF'
env: production
app_port: 80
EOF

cat > group_vars/web.yml <<'EOF'
app_name: demoapp
EOF

示例:group_vars_demo.yml

- name: group_vars demo
  hosts: web
  tasks:
    - name: Show config from group_vars
      command: echo "env={{ env }} app={{ app_name }} port={{ app_port }}"

分别执行:

ansible-playbook -i inventory group_vars_demo.yml -l dev
ansible-playbook -i inventory group_vars_demo.yml -l prod

效果:

  • 环境差异:dev.yml / prod.yml 自动切换
  • 角色共性:web.yml 统一复用
  • Playbook 不改一行

五、注册变量

1. 工作原理

graph LR
    A[执行命令任务] --> B[register 注册结果]
    B --> C[访问输出字段]
    C --> D[后续任务使用]

mermaid

register 工作流程

2. 最小可用示例

示例:register_demo.yml

- name: register demo
  hosts: dev
  tasks:
    - name: Get hostname
      command: hostname
      register: hostinfo

    - name: Print hostname and rc
      command: echo "hostname={{ hostinfo.stdout }} rc={{ hostinfo.rc }}"

执行:

ansible-playbook -i inventory register_demo.yml

关键字段:

  • stdout:命令标准输出
  • rc:返回码(0 通常表示成功)

六、变量设计最佳实践

1. 五条黄金规则

A. 环境差异放 group_vars/dev.yml、group_vars/prod.yml

例如:端口、域名、开关参数、数据库连接信息

B. 角色共性放 group_vars/web.yml、group_vars/db.yml

例如:应用名、日志目录、配置路径

C. 主机变量只解决"个例"

例如:某台机器 SSH 用户不同、端口不同。不要把环境差异写成一堆主机变量。

D. 同名变量只在一个地方定义

同名变量出现在多个文件/位置是排错噩梦。工程中建议用"约定"固定变量定义位置。

E. 变量命名要可读,避免缩写

推荐:app_port、db_host
避免:p、h

2. 变量组织架构

graph TD
    A[变量分类] --> B[环境差异变量]
    A --> C[角色共性变量]
    A --> D[主机个例变量]

    B --> E[group_vars/dev.yml]
    B --> F[group_vars/prod.yml]

    C --> G[group_vars/web.yml]
    C --> H[group_vars/db.yml]

    D --> I[Inventory 主机变量]

    style B fill:#fff3e0
    style C fill:#e8f5e9
    style D fill:#fce4ec

mermaid

变量组织架构

七、学习检查清单

学完本篇内容,你应该能够做到:

  • 会用三种方式定义变量(vars / Inventory / -e)
  • 通过实验验证优先级,不再靠猜
  • 会用 vars_files 和 group_vars 做变量工程化
  • 会用 register 拿到命令输出并继续使用
  • 变量结构按环境差异/角色共性/主机个例组织

如果你已经能做到:一套 Playbook 适配 dev/prod 不改一行,那这篇就学到位了。


参考资料

  1. 变量用不好,Ansible 就废了一半-第7篇
最后修改:2026 年 01 月 15 日
如果觉得我的文章对你有用,请随意赞赏