簡體   English   中英

Python多處理崩潰了docker容器

[英]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

ref: Docker和PID 1僵屍收割問題(phusion.nl)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM