注意
本文针对的是 Docker Compose V1(Python 版,命令是 docker-compose
),可能和您使用的 Docker Compose 版本不同。目前 Docker Compose 的最新版本是 V2(Go 语言版,命令是 docker compose
)。更多信息请参阅官方文档 History and development of Docker Compose 和 Migrate to Compose V2。
当 Linux 系统随机数熵不足时,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.3
和 4.2.0
。
另一种方案:安装 haveged
¶
Haveged 可以解决在某些情况下,系统熵过低的问题。在 Debian、Ubuntu 等系统直接安装即可:
apt-get update && apt-get install -y haveged