如何检测Ansible playbook在执行期间挂起的原因

68

我写的一些任务始终未能完成。即使使用-vvvv选项,Ansible也没有提供任何可以解释此问题的错误或日志。Playbook只是挂起,经过数小时后仍然没有变化。

当我尝试手动运行任务(通过SSH输入命令)时,一切都正常。

以下是一个卡住的示例任务:

- name: apt upgrade
  shell: apt-get upgrade

有没有办法查看stdout和stderr?我尝试过:

- name: apt upgrade
  shell: apt-get upgrade
  register: hello
- debug: msg="{{ hello.stdout }}"
- debug: msg="{{ hello.stderr }}"

但是并没有什么改变。

我确实拥有所需的权限,而且我输入了正确的sudo密码 - 其他需要sudo权限的任务都能正确执行。


你正在传递 -K 选项吗? - flynfish
是的。但我的问题在这里得到了解决 https://groups.google.com/forum/#!topic/Ansible-project/mm99yAPVrfc - dev9
6
好的,你应该将解决方案作为答案发布并进行自我接受。这样其他人查看该问题时会更有帮助。 - flynfish
9个回答

25

你遇到的问题最有可能是SSH连接的问题。当任务需要长时间执行时,SSH会发生超时。我曾经遇到过这样的问题,为了克服SSH超时的问题,在运行Ansible的当前目录中创建一个ansible.cfg文件,并添加以下内容:

[ssh_connection]

ssh_args = -o ServerAliveInterval=n

当通过SSH连接到服务器时,n是ServerAliveInterval(秒),我们在连接过程中使用它。将其设置为1-255之间。这会导致ssh客户端每隔n秒向服务器发送空数据包,以避免连接超时。


9
以下设置解决了我的问题: [ssh_connection] ssh_args = -o ServerAliveInterval=30 -o ControlMaster=auto -o ControlPersist=60s - Yamir Encarnacion
6
一则小提示:仅使用ServerAliveInterval=100会减慢执行ansible任务的速度。您需要将其与ControlMaster=auto -o ControlPersist=10m结合使用。 - TroodoN-Mike

19

我之前使用一本playbook时也遇到了相同的问题。

它一开始能够完美运行,但在某个时间点停止了,所以我加入了asyncpoll参数来避免这种行为。

- name: update packages full into each server
  apt: upgrade=full
  ignore_errors: True
  async: 60
  poll: 60

它像魔法一样奏效了!我真的不知道发生了什么,但现在似乎Ansible会考虑正在发生的事情,不再冻结了!

希望这能有所帮助。


9
发生的情况是,ansible不再坐等命令执行(并在ssh连接超时后失败),而是会定期检查命令执行情况——在本例中每60秒检查一次,最多检查60秒(也就是一次)。这样可以避免ssh连接超时的问题。 - Sirex

7

我曾遇到同样的问题,经过一番小折腾,我发现问题出在收集事实的步骤上。以下是一些提示,可帮助您更好地解决类似问题。

在playbook中禁用事实收集:

---
- hosts: myservers
  gather_facts: no
..

重新运行playbook。如果它能正常工作,那么问题不在SSH本身,而是在收集事实的脚本中。我们可以很容易地调试这个问题。
  1. SSH到远程主机
  2. .ansible文件夹中找到setup文件。
  3. 使用./setuppython -B setup运行它

如果它卡住了,那么我们就确定问题确实出在这里。要找出导致它卡住的原因,您可以简单地使用编辑器打开文件,并在Factspopulate()方法中添加print语句。重新运行脚本并查看其运行时间。

对我来说,问题似乎是在self.facts['fqdn'] = socket.getfqdn()一行尝试解析主机名时出现的,通过一些谷歌搜索,结果发现这是一个解析远程主机名的问题


2
如果我的.ansible目录没有设置文件,只有一个./tmp目录,而且也是空的,那该怎么办? - Josiah

6
在我的情况下,Ansible一直“挂起”,因为apt-get试图询问我一个问题!我是如何发现这个问题的?我去目标服务器上运行了ps -aef | grep apt命令,然后在适当的“卡住”的apt-get命令上执行了kill命令。
在我执行该命令之后,我的Ansible Playbook立即恢复正常,并使用ansible-playbook -vvv选项报告结果:
    " ==> Deleted (by you or by a script) since installation.",
    " ==> Package distributor has shipped an updated version.",
    "   What would you like to do about it ?  Your options are:",
    "    Y or I  : install the package maintainer's version",
    "    N or O  : keep your currently-installed version",
    "      D     : show the differences between the versions",
    "      Z     : start a shell to examine the situation",
    " The default action is to keep your current version.",
    "*** buildinfo.txt (Y/I/N/O/D/Z) [default=N] ? "

阅读了那些有用的诊断输出后,我立刻意识到需要一些适当的dpkg选项(例如,请参见这篇DevOps文章)。在我的情况下,我选择了:

apt:
  name: '{{ item }}'
  state: latest
  update_cache: yes
  # Force apt to always update to the newer config files in the package:
  dpkg_options: 'force-overwrite,force-confnew'
loop: '{{ my_packages }}'

此外,不要忘记使用类似于以下命令清理已终止的Ansible会话,否则您的安装可能仍然会失败:
sudo dpkg --configure -a

1
这里有类似的情况。在我的情况下,我在一个简单创建临时目录的任务中添加了 delegate_to: localhost。看到你的帖子后,我仔细查看并发现ansible进程中有 sudo。于是我在该任务中添加了 become: false,问题得以解决。 - fbicknel

3

这对我来说是一个完全不同的解决方法。 我从Debian Jessie(Linux PwC-Deb64 3.16.0-4-amd64#1 SMP Debian 3.16.7-ckt25-2+deb8u3(2016-07-02)x86_64 GNU / Linux)到另一个我正在尝试在AWS中构建的Debian映像。

在这里的许多建议都没有为我工作,我怀疑SSH“共享”连接。 我去了我的ansible.cfg并找到了ssh_args行,并设置ControlMaster=no。 现在可能会执行得很慢,因为我已经失去了这应该给的SSH性能提升,但似乎存在某种交互作用,这与apt-get导致问题。

您的ansible.cfg可以在您运行ansible的目录中,也可以在/etc/ansible中。 如果是后者,在开始更改之前,您可能需要将其复制到本地目录中!


1

我的情况是Ansible尝试运行的命令需要额外的tty输入。我能够在远程机器上运行ps -aef并找到最后一个通过的命令。我重新运行了该命令,并发现它确实需要除ansible已经完成的sudo密码输入之外的额外sudo密码输入。幸运的是,我可以不使用该组件,因此我只需从脚本中删除它。

更健壮的解决方案是在/etc/sudoers文件中禁用requiretty。但是,如果您这样做,请确保在脚本运行后恢复它,因为禁用该设置会带来安全隐患。


1
一个适用于数千个主机(/tmp/hosts)的任务一行代码,在timeout工具控制下执行。 该脚本将主机列表分割成块(每块25个),并控制每个块的执行,直到超时(600秒)。 如果超时时间超过限制,timeout工具会在此迭代中终止ansible-playbook的运行。 这样可以避免因僵尸进程而停止ansible-playbook的执行。
ANSIBLE_HOST_KEY_CHECKING=False /bin/bash -c 'while mapfile -n 25 ary && ((${#ary[@]})); do echo "${ary[@]}" | tr -d " " > /tmp/hosts.chunk; timeout 600 /usr/bin/ansible-playbook -v -b -i /tmp/hosts.chunk -u ansible -e "var_url_deb=https://server/files/pkg.deb" /var/www/html/git/remediations-gendbuntu/utils/unique-tasks/install-url-deb.yml; done < /tmp/hosts'

仓库链接:https://github.com/skosachiov/remediations-gendbuntu/blob/main/utils/unique-tasks/at-template.sh

0

我正在使用ansible在Ubuntu 20.4虚拟机上安装OpenDayLight SDN控制器集群。收集事实时报告了Python版本警告并挂起。在我的3个VM工作节点上安装Python 3.8解决了该问题。


0

删除我的SSH密钥的密码对我来说解决了这个问题,例如:

ssh-keygen -p

10
4月1日回答?干得漂亮,先生。 - 0xSheepdog
1
真遗憾,但这确实是我的解决方案。即使使用了-k选项和sshpass,仍然会出现卡顿的情况。将来必须寻找适当的解决方案。 - Jack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接