6

Patch docker-compose 防止启动时卡住

 3 years ago
source link: https://phuker.github.io/patch-for-docker-compose-hanging.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文主要解决 docker-compose 命令启动时,随机卡住几秒至几分钟才有反应的问题。本文主要复制/翻译洒家在这个 issue 中的评论。

TL;DR

如果你只在 Linux 本机使用 docker-compose,不使用 docker-compose 的远程功能(例如 -H 参数,DOCKER_HOST 环境变量),按下面方式 patch 1 行代码即可解决问题。

首先定位 docker-compose 使用的 docker 库文件位置。根据 Python 的版本,一般位于 /usr/local/lib/[YOUR_PYTHON_VERSION]/dist-packages/docker/transport/__init__.py。如果找不到,可以按下文提到的方法定位此文件。

编辑此文件,将 from .sshconn import SSHHTTPAdapter 替换为 SSHHTTPAdapter = None 即可。

try:
    # add this line
    SSHHTTPAdapter = None

    # # comment this line
    # from .sshconn import SSHHTTPAdapter
except ImportError:
    pass

运行 docker-compose version 测试,你会发现再也不会卡了,而且在低配机器上启动速度还快了不少。

附:顺腾摸瓜定位文件

以洒家的某台虚拟机为例,运行命令:

# docker-compose version
docker-compose version 1.25.4, build unknown
docker-py version: 3.7.3
CPython version: 2.7.17
OpenSSL version: OpenSSL 1.1.1  11 Sep 2018

docker-compose 是在 Python 2.7.17 上安装的。用相同版本的 Python 运行 pip:

# python2 -m pip show docker
Name: docker
Version: 3.7.3
Location: /usr/local/lib/python2.7/dist-packages

根据上述命令输出的 Location,找到目标文件 /usr/local/lib/python2.7/dist-packages/docker/transport/__init__.py

附:暴力定位文件

搜索整个根目录:

# find / -type f -name __init__.py 2>/dev/null | grep docker/transport/__init__.py
/usr/local/lib/python2.7/dist-packages/docker/transport/__init__.py

解释

即使只是运行一条简单的 docker-compose version 命令,docker-compose 也会加载所有可能用到的库。docker-compose 依赖 docker 库,为了实现远程 SSH 功能,docker 库依赖 paramiko 库,paramiko 又依赖 pynacl 库。pynacl 是对 libsodium 的封装。在 libsodium 初始化的时候,系统随机数熵(entropy)需要高于 160,否则会一直等待。

查看当前系统随机数熵值:

# cat /proc/sys/kernel/random/entropy_avail
105

使用性能分析工具可以看到各种库的加载过程,以及卡住的位置:

# python2 -m cProfile `which docker-compose` --version
docker-compose version 1.24.1, build 4667896
         130382 function calls (126780 primitive calls) in 112.339 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 <string>:1(ArgInfo)
        ......
        2    0.001    0.000  112.085   56.043 __init__.py:15(<module>)
        1    0.001    0.001  112.142  112.142 __init__.py:20(<module>)
        1    0.005    0.005  112.152  112.152 auth.py:1(<module>)
        2    0.001    0.000  112.153   56.077 build.py:1(<module>)
        2    0.003    0.001  112.211   56.106 client.py:1(<module>)
        1    0.000    0.000  112.144  112.144 decorators.py:1(<module>)
        1    0.001    0.001  112.343  112.343 docker-compose:3(<module>)
        1    0.000    0.000  112.087  112.087 ed25519key.py:17(<module>)
        1    0.003    0.003  112.333  112.333 main.py:1(<module>)
        1    0.000    0.000  112.086  112.086 signing.py:15(<module>)
        1    0.000    0.000  112.084  112.084 sodium_core.py:21(_sodium_init)
        1    0.000    0.000  112.084  112.084 sodium_core.py:27(sodium_init)
        1    0.000    0.000  112.142  112.142 sshconn.py:1(<module>)
        1    0.000    0.000  112.143  112.143 tls.py:1(<module>)
        1    0.004    0.004  112.139  112.139 transport.py:22(<module>)
        4    0.000    0.000  112.144   28.036 utils.py:1(<module>)
        1  112.084  112.084  112.084  112.084 {built-in method sodium_init}
        1    0.000    0.000  112.084  112.084 {method 'init_once' of 'CompiledFFI' objects}
        ......

因此,直接 patch 代码,防止这一堆和 SSH、密码学有关的不必要的库加载和初始化即可解决问题。洒家测试过的 docker 库版本有:3.7.34.2.0

另一种方案:安装 haveged

Haveged 可以解决在某些情况下,系统熵过低的问题。在 Debian、Ubuntu 等系统直接安装即可:

apt-get update && apt-get install -y haveged

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK