2

直接从 a 运行 python shell 时docker-compose run,父 PID 显示为 0,感觉很不对劲。我在下面整理了一个非常简单,可重现的案例:

# Dockerfile
FROM python:3.7-buster
COPY . /code/
WORKDIR /code
# docker-compose.yml
version: '3'

services:
  thing:
    build: .
    volumes:
      - .:/code

当我在其中运行 python shell 时,它的 ppid 为 0;同样以这种方式运行的任何 python 代码(例如,如果运行测试pytest):

$ docker-compose run thing python
>>> import os
>>> os.getpid()
1
>>> os.getppid()
0

当我从 bash shell 中运行 python shell 时,我看到了一个更理智的值......

$ docker-compose run thing bash
root@<id> # python
>>> import os
>>> os.getpid()
6
>>> os.getppid()
1

当我直接在我的主机上运行 python shell 时,我还看到了更多理智的 PID 值......

$ python
>>> import os
>>> os.getpid()
25552
>>> os.getppid()
1133

我确信这是关于如何docker处理正在运行的容器中的进程的一些奇怪行为,但在我看来,PID 不应该是 0。这是预期的行为吗,如果是,是否有运行 Python 代码的解决方法这种依赖父PID的方式?

4

2 回答 2

2

这既不奇怪也不错误——父 PID 为 0,因为Docker 容器中没有父进程

当运行类似的东西时docker-compose run thing python,在该容器中(或更准确地说,在该PID 命名空间中)启动的第一个进程将是该进程本身。因此,它将获得 PID 1 并且它不会有父进程。python

注意:完全相同的事情也发生在常规(非容器化)Linux 系统上;PID 为 1 的进程也是第一个进程(在这种情况下,由内核在引导后启动)并且通常是像systemd这样的 init 系统。然后 init 系统处理启动 Linux 系统的用户空间部分(例如设置网络、挂载文件系统和启动系统服务)——在 Docker 容器中,通常不需要任何这些,这也消除了需要任何初始化系统。但是,有一些初始化系统,比如哑初始化,它们是专门为在容器中运行而设计的。

在容器中运行 shell 并从该 shell 启动 Python 时,shell 将是 PID 1。在这种情况下,os.getppid()从 Python 脚本运行应该返回1.

这是预期的行为吗,如果是这样,是否有一种解决方法可以让 Python 代码以这种方式运行,它依赖于父 PID?

如前所述,您可以从 shell(或任何其他进程,就此而言)启动您的 Python 环境,然后获得 PID 1 而不是 python。您还可以使用为容器设计的初始化系统,例如dumb-init.

于 2020-01-03T21:11:35.680 回答
0

这是预期的行为。容器内的主进程是 PID 1 并且没有父进程。这是容器隔离的一部分——进程似乎是整个系统中唯一的进程。

当我从 bash shell 中运行 python shell 时,我看到了一个更理智的值......

在那种情况下,根进程是 bash 并且它有一个 python 子进程。

于 2020-01-03T20:54:01.320 回答