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 |
|---|---|---|---|
| dev | web | dev-web1 | 192.168.10.11 |
| dev | web | dev-web2 | 192.168.10.12 |
| dev | db | dev-db1 | 192.168.10.21 |
| test | web | test-web1 | 192.168.10.31 |
| test | db | test-db1 | 192.168.10.41 |
| prod | web | prod-web1 | 192.168.10.51 |
| prod | web | prod-web2 | 192.168.10.52 |
| prod | db | prod-db1 | 192.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.ymlB. 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:#4fc3f7A. 验证实验 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[后续任务使用]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七、学习检查清单
学完本篇内容,你应该能够做到:
- 会用三种方式定义变量(vars / Inventory / -e)
- 通过实验验证优先级,不再靠猜
- 会用 vars_files 和 group_vars 做变量工程化
- 会用 register 拿到命令输出并继续使用
- 变量结构按环境差异/角色共性/主机个例组织
如果你已经能做到:一套 Playbook 适配 dev/prod 不改一行,那这篇就学到位了。