好久没更了。Ansible也算在微博搬砖接触比较多的东西,通过调用其api可以自定义批量配置下发通道,Ansible官方也有Ansible-Tower(然而没开源且付费)。国内少有人尝试api2.0,这里就稍微写一写。

调用Ansible的手段

  • 通过命令
    • 直接起新进程命令调用Ansible,也有不错的项目是这么做的: Semaphore,看了看代码,原理上其实是每次从一个git仓库克隆playbook到本地,然后把hosts写成tmp文件,直接起新进程调命令执行,即时日志输出通过绑定标准输出来取得。
    • 这种方案语言无关,而且不大容易受api变动影响,个人也很推荐。(然而要写好多临时文件)
  • 通过API
    • 通过api调用和命令调用的区别其实只是Playbook和Inventory的来源是否从文件读取。就算是调用api,每次依然都要走完整的初始化流程,且默认的日志要打在标准输出上。
    • Ansible从1.x迁移到了2.x重构了大量代码,这也导致Api 1.x和2.x完全不一样,文档少的可怜,能参考的基本只有看代码。

下面说说方法二

调用流程

首先贴个官方文档,里面只有个最简单的demo: Ansible-api

因为某些蛋疼的缘故,把Ansible执行的关键代码走了一遍,大致说下api的执行流程:

  • 准备,在执行前,需要初始化三个实例:

    • Inventory: 相当于hosts文件,可包含多个ip或者ip-group,在这里指明连接方式( password或者ssh_key )
    • VariableManager: 在这里配置Playbook中对应变量的值
    • __ PlaySource__: 相当于Playbook文件,指定运行的任务,调用的role等等
  • 连接并执行,通过Ansible的TaskQueueManager,默认调用其中的linear strategy执行

    • 解释: 具体没研究,Playbook语法 => python源代码
    • 打包: 解释后的python源代码,压缩成字符串,拼上Ansible的最小执行环境成一个py文件
    • 连接: 根据-f参数或配置,fork多个进程调用ssh连接到目标机(ssh_key或密码),上传打包的代码,执行
    • 执行(远端): 将压缩字符串解压写成多个py文件(对应命令),起新进程(popen())逐个执行,绑定输出到管道,一次性读取,通过ssh连接返回json格式数据
    • 回报: 分发机接到json格式返回值并解析,打到标准输出(单步状态返回)
  • 回报并清理,最后由TaskQueueManager清理资源 (fork出的多个连接进程)

其他注意事项

  • SSH连接: password OR private_key

    • 密码登录省点事。private_key的话不支持从字符串读取,每个ip对应一个ssh文件,所以最后是写缓存文件解决。(顺带一提权限要给600)。
  • API调用线程不安全: not thread safe

    • 之前说过,Ansible即使通过api调用,也要走一套完整的初始化流程,包括加载内置的各类plugin。
    • 因为项目涉及批量配置下发,自然多线程调用Ansible成为首选,然而发现总是出现不明所以的报错,在多个Ansible线程同时启动时尤为明显,google之,发现问题所在:issue #13823
    • 问题原因: 看源码的/ansible/plugins/init.py这里, 注意到第42行,有三个全局变量,这是Ansible的缓存,保存加载后的plugin。然而一个plugin在还必须执行init()方法才能初始化完成。 众所周知,多线程下共享全局变量,这样多线程竞争时,某个线程就会把未初始化完成的plugin当作初始化完成的使用,自然会报错。
    • 【 解决方法: 既然竞争,干脆不共享算了,多进程算了.....
  • 单个任务停止:

    • 因为Ansible这东西的一个特性是幂等性,你中间强行杀掉铁定官方是不滋瓷的,所以要强行实现
    • 起初的实现是,分发新任务时记下进程pid,停止时杀死此进程。 然而发现,远端机的执行并未停止....
    • 问题原因: 调用Ansible的进程只是管理进程,真正建立连接执行的是子进程,杀死管理进程不仅停不掉远端任务,还会留下僵死进程消耗资源。
    • 解决方法: 停止时先对Ansible管理进程发送SIGSTOP信号阻止进一步fork, 然后调用ps命令查询管理进程的子进程,逐个发送SIGKILL,最后杀死管理进程

总结

其实还有自定义callback和module可以写写,之后填坑吧(大概也不会填)

总之感觉Ansible这东西,大概最大的优点就是简单, 虽然名义上避免了agent, 但是写临时文件执行py代码其实也差不多。

国内文档也是少的就没有, 自己折腾一套踩了一堆坑, 好在最后是把东西做出来了。

不过折腾这两周, 学的东西大概还是不少, 希望之后能把混合云开源跟完吧。

(没了..)