Python bug导致ansible gather facts超时而执行失败

Python bug 导致 ansible-playbook 在执行 gather facts 时因尝试关闭错误的文件描述符数量超时而执行失败。

Python bug导致ansible gather facts超时而执行失败

背景

我们在CentOS7 上使用 Ansible执行 kubespray的playbook时,遇到一个问题:

执行lsblk始终超时,错误如下:

FAILED! => {"changed": false, "cmd": "/usr/bin/lsblk --list --noheadings --paths --output NAME,UUID --exclude 2", "msg": "Timer expired after 10 seconds", "rc": 257}

image

而我们将单个命令拿到具体的节点上执行时,又可以顺利通过:

/usr/bin/lsblk --list --noheadings --paths --output NAME,UUID --exclude 2

排查

经过反复的排查、搜索,最后发现它是Python的一个Bug,Ansible在调用 python执行远程任务时,由于我们做了系统优化,调整了每台节点用户能打开文件描述符的上限(6000000),这竟然导致python在执行Gathering facts指令时,按照这个描述符上限数量去关闭文件,而不是按照实际打开的描述符数量去关闭,这个关闭过程在10s(10s是ansible的gather_timeout默认值)内不能完成,Ansible认为任务超时,直接退出playbook的执行。

此Bug影响范围经官方确认是:Python 3.1, Python 3.2, Python 3.3, Python 2.7,但实际上 Python 3.x 都存在,并且是一个 WONTFIX 的状态。

Ansible issue: https://github.com/ansible/ansible/issues/24785
Python issue: https://bugs.python.org/issue11284

解决

解决这个问题的办法有3个:

  • 退回 centos6, 或者使用 virtualEnv 使用 python2.6 去运行 kubespray,可以正常通过;

  • 调整我们系统优化中 soft nprocsoft nofile 的值到 100000,在centos7 上也能正常通过了:
    image

  • 修改目标机器的 ansible 模块文件,在本地修复 bug
    vim /usr/lib/python2.7/site-packages/ansible/plugins/shell/__init__.py
    注释 201行,并添加 202,203 行:

    197         if shebang:
    198             shebang = shebang.replace("#!", "").strip()
    199         else:
    200             shebang = ""
    201         #cmd_parts.extend([env_string.strip(), shebang, cmd])
    202         ulimit = os.environ.get('ANSIBLE_ULIMIT', '4096')
    203         cmd_parts.extend(['ulimit -n {0};'.format(ulimit), env_string.strip(), shebang, cmd])
    

    此部分参考:
    'setup' stage takes too long time on linux server host with large max-open-files config
    Workaround to speed up facts building