简体   繁体   English

Python多处理崩溃了docker容器

[英]Python multiprocessing crashes docker container

There is simple python multiprocessing code that works like a charm, when I run it in console: 当我在控制台中运行时,有一个简单的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()

Result: 结果:

> $ python3 mp.py
something

Then I've created a simple Docker container with Dockerfile: 然后我用Dockerfile创建了一个简单的Docker容器:

FROM python:3.6

ADD . /app
WORKDIR /app

And docker-compose.yml: 和docker-compose.yml:

version: '3.6'

services:
  bug:
    build:
      context: .
    environment:
      - PYTHONUNBUFFERED=1
    command: su -c "python3.6 forever.py"

Where forever.py is: 其中forever.py是:

from time import sleep

if __name__ == '__main__':
    i = 0
    while True:
        sleep(1.0)
        i += 1
        print(f'hello {i:3}')

Now I run forever.py with docker compose: 现在我用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

Up to this moment everything is good and understandable. 到目前为止,一切都很好,可以理解。 But when I'm trying to run mp.py in the docker container it crashes without any message: 但是,当我试图在mp.py容器中运行mp.py ,它崩溃而没有任何消息:

> $ docker exec -it mpbug_bug_1 /bin/bash
root@09779ec47f9d:/app# python mp.py 
something
root@09779ec47f9d:/app# % 

Gist with the code can be found here: https://gist.github.com/ilalex/83649bf21ef50cb74a2df5db01686f18 可以在这里找到代码的要点: https//gist.github.com/ilalex/83649bf21ef50cb74a2df5db01686f18

Can you explain why docker container is crashed and how to do it without crashing? 你能解释为什么docker容器崩溃以及怎么做而不会崩溃?

Thank you in advance! 先感谢您!

for a quick fix, do not use spawn start method, and/or do not use su -c ... , both are unnecessary IMO. 为了快速修复,不要使用spawn start方法,和/或不使用su -c ... ,两者都是不必要的IMO。 change to: 改成:

p = mp.Process(target=do_smth, args=tuple())

or you could start container with --init option. 或者您可以使用--init选项启动容器。

with spawn start method, Python will also start a semaphore tracker process to prevent semaphore leaking, you could see this process by pausing mp.py in the middle, it looks like: 使用spawn start方法,Python也会启动信号量跟踪器进程以防止信号量泄漏,你可以通过在中间暂停mp.py看到这个过程,它看起来像:

472   463 /usr/local/bin/python3 -c from multiprocessing.semaphore_tracker import main;main(3)

this process is started by mp.py but exited after mp.py , thus it will not be reaped by mp.py , but is supposed to be reaped by init by design. 这个过程由mp.py启动但在mp.py之后退出,因此它不会被mp.py收获,但应该由init设计获得。

the problem is there is no init in this container(namespace), instead of init , PID 1 is su -c , therefore the dead semaphore tracker process is adopted by su . 问题是这个容器(命名空间)中没有init ,而不是init ,PID 1是su -c ,因此su采用了死信号量跟踪器进程。

it appears that su consider the dead child process is the command process( forever.py ) mistakenly, without checking the relationship, so su exit blindly, as PID 1 exit, kernel kills all other processes in the container, including forever.py . 看来su认为死子进程是命令进程( forever.py )错误,没有检查关系,所以su盲目退出,当PID 1退出时,内核杀死容器中的所有其他进程,包括forever.py

this behavior could be observed with strace : strace可以观察到这种行为:

docker run --security-opt seccomp:unconfined --rm -it ex_bug strace -e trace=process -f su -c 'python3 forever.py'

will output error message like: 将输出错误信息,如:

strace: Exit of unknown pid 14 ignored

ref: Docker and the PID 1 zombie reaping problem (phusion.nl) ref: Docker和PID 1僵尸收割问题(phusion.nl)

mp.py doesn't look like an equivalent of forever.py . mp.py看起来不像的等效forever.py mp.py will run new worker process, which will just print something and then it will exit => join() in the main process will exit immediately, when this worker process is done. mp.py将运行新的工作进程,它将只打印something ,然后它将退出=>主进程中的join()将在此工作进程完成时立即退出。

Better equivalent of forever.py : worker process prints hello message in the infinite loop and main process will be waiting for this worker process exit in join() - forever-mp.py : 更好等价于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()

Updated docker-compose.yml : 更新了docker-compose.yml

version: '3.6'

services:
  bug:
    build:
      context: .
    environment:
      - PYTHONUNBUFFERED=1
    command: su -c "python3.6 forever-mp.py"

Test: 测试:

$ 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

Check processes in the container: 检查容器中的进程:

$ 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