两套变量目录决定谁能被覆盖
角色里有两处放变量的地方,优先级完全不同:默认值目录的变量优先级最低,几乎任何外部定义都能覆盖它;角色变量目录的优先级高于清单里的分组变量。于是它们承担不同职责:默认值目录是角色的对外接口,列出所有可调参数;角色变量目录放内部常量,调用方不需要也不应该去改。
基本信息
| 默认值目录 | 对外参数,可被清单变量、剧本变量、传参覆盖 |
|---|---|
| 角色变量目录 | 内部常量,优先级高于清单分组变量,外部不易覆盖 |
| 传参方式 | 在角色引用处直接给变量,优先级高于以上两者 |
| 命名建议 | 对外参数统一加角色名前缀,避免与其它角色或清单变量撞名 |
| 秘密处理 | 默认值里不写真实秘密,只声明需要调用方提供 |
| 验证方法 | 打印最终取值,或对照变量优先级文档确认覆盖链 |
典型使用场景
- 对外提供可调参数:端口、路径、工作进程数放进默认值目录
- 内部固定取值:包名、服务单元名、内部目录布局放进角色变量目录
- 多环境取值不同:环境差异通过清单变量覆盖默认值,角色本身不变
- 单点覆盖:某个主机需要不同参数时用主机变量覆盖,不影响其它主机
- 临时试验:用额外变量在命令行临时覆盖取值,验证后再落到清单
- 接口收敛:默认值目录成为角色文档,调用方一眼看到可调项
两套目录的分工
两套目录的分工
# roles/app/defaults/main.yml 对外接口,可被外部覆盖
# app_port: 8080
# app_worker_processes: 2
# app_log_level: info
# app_conf_dir: /etc/app
# roles/app/vars/main.yml 内部常量,不该被环境差异影响
# app_service_name: app
# app_pkg_name: app-server
# app_state_dir: /var/lib/app
# 调用方覆盖的三种方式
- hosts: web
roles:
- role: app
vars:
app_worker_processes: 8 # 角色传参,优先级最高
tasks:
- name: 临时查看最终取值
ansible.builtin.debug:
var: app_worker_processes
# 清单侧覆盖(优先级低于角色变量目录,高于默认值)
# group_vars/web/vars.yml
# app_log_level: debug覆盖优先级直觉版
| 定义位置 | 相对高低 | 用途 |
|---|---|---|
| 角色默认值目录 | 最低 | 对外接口与兜底值 |
| 清单分组变量与主机变量 | 较高 | 环境与主机差异 |
| 角色变量目录 | 高 | 角色内部常量 |
| 角色引用处传参 | 更高 | 调用方明确指定 |
| 命令行额外变量 | 最高 | 临时覆盖,排障与试验 |
覆盖不生效时,先怀疑三件事:参数写在了角色变量目录(优先级过高)、参数名拼写或前缀不一致、覆盖写在了优先级更低的位置。用调试任务打印最终取值,比反复改文件快得多。
把需要按环境调整的取值写进角色变量目录,会让外部覆盖失效,调用方只能去改角色代码,复用性随之丧失。凡是“别人可能想调”的参数,一律放默认值目录。
接口设计的判断
一个成熟角色的默认值目录应当像一份参数说明:变量名带前缀、有合理兜底、注释写清用途与取值范围。凡是调用方需要知道内部实现才能传对的参数,说明接口还没设计好——要么补默认值,要么把它变成内部常量。