背景问题
我们的运维平台是基于 SaltStack 封装的任务系统.
在任务系统上将需要执行多个操作转为不同的 state
SaltStack 负责进行调度执行, Minion 执行完了之后, 会将数据结果返回给 master
而 master 则将结果保存在 mongodb 里面, 看图
然而, 在我们使用的时候出现个奇怪的问题
第一个主机上的 state 执行是成功
但是莫名其妙会在第二个个主机上执行 state
幸好没执行成功, 不然尽给我瞎整.
分析排查
基本测试
先看看这个主机在 master 上是否能正常连接.
执行命令salt "VM_0_7_centos" test.ping
结果显示无法连接
再看看 salt-minon 的 key 是否还存在
执行命令salt-key -L | grep "VM_0_7_centos"
结果显示, 这台主机 salt-minion 的 key 并不存在
这就很尴尬了, 为什么一台不存在的主机会被state.sls
执行到.
关键还不是必现的问题, 不好排查.
查看源码
这个问题奇怪的很, 而且不是必现.
网上也找不到什么有用的信息.
好在 SaltStack 是一个开源的项目.
有什么不清楚的, 我们可以直接看源码来排查.
其实对 SaltStack 不是很了解, 代码太长, 我们直接找到问题的核心代码
1 | # |
最终发现/var/cache/salt/master/minions/
目录里没有相应 minion 的 cache 信息
而/etc/salt/pki/minions/
上却有相应的 minion 密钥
复盘思考
问题的思考
- 因为主机下线后没有清掉相应的 key 文件导致的
- 使用了 IP 匹配模式来查找 minion
- IP 匹配模式默认使用贪婪模式
很明显, 不了解的原理导致的问题, 反省, 反省, 反省.
设计的思考
我们原本理解的直接指定 IP 地址效率会更高(主机之间通过 IP 地址通过)
而且主机名会变, 但 IP 地址一般来说不会变, 所以我们使用 IP 地址来执行
然而从代码上来看并不是这样的
在 salt-master 寻找 minion 时通过 minion 的 IP 地址的来过滤相应的 minion
这个实现的过滤方式还有点奇怪
一般来说, 我们的实现思路应该是这样的
1 | def find(list, key): |
而 saltstack 上实现的方法则是
1 | def find(list1, list2, key): |
这个设计可能是为了满足贪婪模式, 但这个贪婪模式不清楚是为什么.
从使用者的角度来看, 感觉这是个欠妥的设计.
因为使用时已经明确的指定了对某一个 IP 执行某个动作
但贪婪模式却尽可能的给我匹配更多的 minion
在认知和实现上有较大的差距, 虽然这个可能是使用者不当造成的.
但在设计时应该尽量避免这种有明显不同的地方.