[英]Python multiprocessing crashes docker container
當我在控制台中運行時,有一個簡單的python多處理代碼,就像魅力一樣:
# mp.py
import multiprocessing as mp
def do_smth():
print('something')
if __name__ == '__main__':
ctx = mp.get_context("spawn")
p = ctx.Process(target=do_smth, args=tuple())
p.start()
p.join()
結果:
> $ python3 mp.py
something
然后我用Dockerfile創建了一個簡單的Docker容器:
FROM python:3.6
ADD . /app
WORKDIR /app
和docker-compose.yml:
version: '3.6'
services:
bug:
build:
context: .
environment:
- PYTHONUNBUFFERED=1
command: su -c "python3.6 forever.py"
其中forever.py
是:
from time import sleep
if __name__ == '__main__':
i = 0
while True:
sleep(1.0)
i += 1
print(f'hello {i:3}')
現在我用docker compose運行forever.py
:
> $ docker-compose build && docker-compose up
...
some output
...
Attaching to mpbug_bug_1
bug_1 | hello 1
bug_1 | hello 2
bug_1 | hello 3
bug_1 | hello 4
到目前為止,一切都很好,可以理解。 但是,當我試圖在mp.py
容器中運行mp.py
,它崩潰而沒有任何消息:
> $ docker exec -it mpbug_bug_1 /bin/bash
root@09779ec47f9d:/app# python mp.py
something
root@09779ec47f9d:/app# %
可以在這里找到代碼的要點: https : //gist.github.com/ilalex/83649bf21ef50cb74a2df5db01686f18
你能解釋為什么docker容器崩潰以及怎么做而不會崩潰?
先感謝您!
為了快速修復,不要使用spawn
start方法,和/或不使用su -c ...
,兩者都是不必要的IMO。 改成:
p = mp.Process(target=do_smth, args=tuple())
或者您可以使用--init
選項啟動容器。
使用spawn
start方法,Python也會啟動信號量跟蹤器進程以防止信號量泄漏,你可以通過在中間暫停mp.py
看到這個過程,它看起來像:
472 463 /usr/local/bin/python3 -c from multiprocessing.semaphore_tracker import main;main(3)
這個過程由mp.py
啟動但在mp.py
之后退出,因此它不會被mp.py
收獲,但應該由init
設計獲得。
問題是這個容器(命名空間)中沒有init
,而不是init
,PID 1是su -c
,因此su
采用了死信號量跟蹤器進程。
看來su
認為死子進程是命令進程( forever.py
)錯誤,沒有檢查關系,所以su
盲目退出,當PID 1退出時,內核殺死容器中的所有其他進程,包括forever.py
。
用strace
可以觀察到這種行為:
docker run --security-opt seccomp:unconfined --rm -it ex_bug strace -e trace=process -f su -c 'python3 forever.py'
將輸出錯誤信息,如:
strace: Exit of unknown pid 14 ignored
mp.py
看起來不像的等效forever.py
。 mp.py
將運行新的工作進程,它將只打印something
,然后它將退出=>主進程中的join()
將在此工作進程完成時立即退出。
更好等價於forever.py
進程在無限循環中打印hello消息,主進程將在join()
等待此工作進程退出 - forever-mp.py
:
import multiprocessing as mp
from time import sleep
def do_smth():
i = 0
while True:
sleep(1.0)
i += 1
print(f'hello {i:3}')
if __name__ == '__main__':
ctx = mp.get_context("spawn")
p = ctx.Process(target=do_smth, args=tuple())
p.start()
p.join()
更新了docker-compose.yml
:
version: '3.6'
services:
bug:
build:
context: .
environment:
- PYTHONUNBUFFERED=1
command: su -c "python3.6 forever-mp.py"
測試:
$ docker-compose build && docker-compose up
...
some output
...
Attaching to multiprcs_bug_1_72681117a752
bug_1_72681117a752 | hello 1
bug_1_72681117a752 | hello 2
bug_1_72681117a752 | hello 3
bug_1_72681117a752 | hello 4
檢查容器中的進程:
$ docker top multiprcs_bug_1_72681117a752
UID PID PPID C STIME TTY TIME CMD
root 38235 38217 0 21:36 ? 00:00:00 su -c python3.6 forever-mp.py
root 38297 38235 0 21:36 ? 00:00:00 python3.6 forever-mp.py
root 38300 38297 0 21:36 ? 00:00:00 /usr/local/bin/python3.6 -c from multiprocessing.semaphore_tracker import main;main(3)
root 38301 38297 0 21:36 ? 00:00:00 /usr/local/bin/python3.6 -c from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=4, pipe_handle=6) --multiprocessing-fork
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.