TT Lab
开始
学习 学习路径 课程

Ansible 实战

变量优先级:先去测,再谈背表

在 TT Lab 中继续学习

一句话总结

在 Ansible 中,可以放置同名变量的位置有二十二个,与其背诵它们的顺序,减少位置的设计更能确实地防止事故。

为什么需要它

“明明在 group_vars 里把端口写成了 8080,显示的却是 9090。”这类报告几乎总是同一个形状。有人着急时在命令行加了 -e 运行,而这件事没有留在任何地方。或者 role 里有 vars/main.yml,它赢过了 play 的 vars_files。

这个问题之所以难,是因为错误的值不会以错误的形式出现。playbook 成功,文件被创建,只是内容不同。语法检查和 lint 都抓不到。能抓到的只有一件事——实际测量“此刻在这个位置上,这个名称解析成什么”。

所以本模块不去抄写官方文档的列表,而是把同一个名称一个位置一个位置地往里放,测量胜者如何变化。测量过一次的人,即使不背表,下次遇到同样的情况也知道先该怀疑什么。

工作原理

官方文档把位置从低到高排列了二十二个。实验中要测量的十二个位置,从低到高写出来是这样。

名次 位置 性质
1 role defaults/main.yml 递出去的“请在外面覆盖”的值
2 inventory group_vars/all 所有主机的底值
3 inventory group_vars/<그룹>(占位符为组名) 各组的值
4 inventory host_vars/<호스트>(占位符为主机名) 各主机的值
5 play vars: 只在这个 play 中
6 play vars_files: 这个 play 读入的文件
7 role vars/main.yml “不要从外面碰”的 role 内部值
8 block vars: 只在 block 内
9 task vars: 只在一个 task 中
10 set_fact 运行中设定的值
11 role 调用参数 调用 role 时传入的值
12 命令行 -e 什么都能赢

这里让人吃惊的有三处。

第一,vars_files 比 play 的 vars: 更高。 在同一个 play 里,写在上面的 vars: 输给了下面读入的文件。这与按顺序用眼睛读的感觉相反。

第二,role 的 defaults 和 vars 正好相反。 它们在同一个 role 目录里并排放着,但 defaults 在最底层,vars 高得多。这个差别就是 role 作者的意图——可以从外面改的值放在 defaults,不能改的值放在 vars。 用别人的 role 时,如果“怎么覆盖都改不了”,那个值就在 vars/main.yml 里。

第三,范围越窄越高。 play < block < task 的顺序不是用来背的,而是规则。把它看作写在窄位置上的人有更具体的意图。

测量用的工具也值得了解。在 inventory 内部的较量,ansible-inventory --list 会以 JSON 显示已经合并好的结果。在 play 内部的较量,插入一个 debug task 运行一下最快。

ansible-inventory -i inventory --list   # 인벤토리 세 자리가 합쳐진 결과
ansible-inventory -i inventory --graph  # 그룹 구조

给 inventory 传目录时有个陷阱。目录中 .ini 扩展名的文件在默认设置下会被忽略(INVENTORY_IGNORE_EXTS)。用 -i 传单个文件时好好的 hosts.ini,一放进目录就消失了。如果一台主机都看不到,先怀疑这一点。

在现场相遇的样子

第一,字典不会合并。 在低位置放 svc_limits: {cpu: "1", memory: 1Gi},在高位置给出 svc_limits: {memory: 2Gi},结果是 {memory: 2Gi}。cpu 消失了。想合并就必须用 combine filter 明确指出。也可以用全局设置 hash_behaviour = merge 来改,但那个设置会改变整个仓库的行为,所以官方文档也不推荐。

第二,-e 无法撤销。 命令行的值比任何位置都高,在 playbook 内部没有覆盖它的办法。用着方便就开始频繁使用,最终“谁在什么时候给了什么”会从记录里消失。只用于事故应对,并且需要团队规则来留下使用过的事实。

第三,减少位置的设计。 比了解表更强的防御,是减少可放同名变量的位置。常见的规则有三条——按环境区分的值只放在 inventory 的 group_vars 一处,role 只把可以从外面改的值放在 defaults 中,-e 只在例外情况下使用。遵守这三条,即使不知道优先级表,也几乎不会出事故。

第四,vars_prompt。 也有运行时向人询问并接收的位置(在 play 的 vars: 和 vars_files: 之间)。在自动化流水线中运行会停住,所以要进入 CI 的 playbook 不要使用。本实验也是自动评分,所以不涉及。

下一项实验要做什么

把 svc_tier 这一个名称,一个位置一个位置地放进十二个位置,亲自测量胜者如何变化。inventory 的三个位置用 ansible-inventory --list,其余的运行 playbook 并用产出物确认。最后把测得的顺序留成人能读懂的表,并排确认字典不会合并,以及用 combine 合并的情形。

参考文档