使用 ansible 在大规模 (几百台以上规模比较容易遭遇) 部署机器的时候, 有时候会碰到 ansible 进程 hang 在某个点上, 这个点不一定每次都一样.
研究了一个下午, 发现 hang 住的时候, CI/CD 的 agent 上并没有报错日志, 被执行 host 上也没有 ansible 的日志输出, 并且无论等待多长时间也不会退出.
期初怀疑是版本问题, 因为之前线上一直用的 2.7 版本, 最近刚切换到 2.9, 但是实际上这个部署的 job 在使用 2.9 版本的时候已经成功过不少次. 然后检查 CI/CD 上部署 job 的 VCS 配置, 发现虽然有更新, 但是并没有什么很大的可能明显导致这种情况发生的 changes.
启动 google 大法, 发现 ansible 的 GitHub 上有人提过一个 issue, 一个很老的 2017 年 9 月的 issue, https://github.com/ansible/ansible/issues/30411
这个 issue 最后一个 comment 是提交了一个 PR(竟然是 20 天前刚提交的), 这个 PR 给 task 执行增加了一个硬超时, 已经 merge, 虽然没有解释为什么会 hang 住, 但是起码提供了一个解决方案. 而且里面的 comments 提到了一个关键的复现方法, 一个简单的 "df" 命令就可以让 ansible 进程 hang 住.
于是我找了两台机器, 装了 nfs,client 端挂载了 server 端的一个目录, 然后把 server 端的 nfs 进程 stop 掉, 这时候在 client 中执行 "df" 命令, 效果等同于进程 hang 住, 原理也很简单, 因为 nfs 链接断掉了,"df" 在等待返回, 等不到就 "假死" 在那里.
再然后, 我配置了一个只有一条 shell 命令的 ansible playbook, 让多台机器 (其中包括了这个 nfs client 节点) 同时运行, 结果果然是 ansible 在执行到这个 nfs client 节点的时候 hang 住再也不动了, 并且如果我重新启动 nfs server 端, ansible 立即就回正常执行完, 说明 ansible 进程没有 "死", 只是一直在 "等待".
现在在回过头来思考, 结论应该是批量开机器的时候, 因为我们用的是 AWS, 在规模很大的情况下, 经常有实例会因为各种特例问题导致某些 task 挂起在机器上, 而这个时候由于 ansible 没有超时机制, 并且! 最关键的来了, ansible 没有收到任何错误值和返回值, 于是就一直在 "等待", 等到海枯石烂.
短期的解决方法, 如果是云平台, 干掉那些 "不正常" 的机器, 重新 run 一次 job, 一般都会解决.
长期的话, 超时是一个可行的方案, 而且 ansible 还需要真正的解决是并行问题, 不要让一个机器的问题导致整个 job 的失败(某一个实例有问题, 那就提示出来, 其他的继续跑).
来源: http://blog.51cto.com/387249/2497465