主机中的PID是什么,在Docker容器内运行的进程是什么?

Luk*_*tas 16 linux pid process docker

在Docker容器中运行了几个进程,它们的PID在容器命名空间中是隔离的,有没有办法弄清楚它们在Docker主机上的PID是什么?

例如,在Docker容器内运行一个Apache Web服务器(我使用Docker Hub中的 Apache + PHP映像),Apache启动时会在容器内创建更多的工作进程.这些工作进程实际上是处理传入的请求.要查看这些进程,我pstree在docker容器中运行:

# pstree -p 1
apache2(1)-+-apache2(8)
           |-apache2(9)
           |-apache2(10)
           |-apache2(11)
           |-apache2(12)
           `-apache2(20)
Run Code Online (Sandbox Code Playgroud)

父Apache进程在容器进程名称空间内的PID 1上运行.但是从主机的角度来看,也可以访问它,但它在主机上的PID是不同的,可以通过运行docker compose命令来确定:

 $ docker inspect --format '{{.State.Pid}}' container
 17985
Run Code Online (Sandbox Code Playgroud)

由此我们可以看到容器进程命名空间内的PID 1映射到主机上的PID 17985.所以我可以pstree在主机上运行,列出Apache进程的子代:

$ pstree -p 17985
apache2(17985)???apache2(18010)
               ??apache2(18011)
               ??apache2(18012)
               ??apache2(18013)
               ??apache2(18014)
               ??apache2(18164)
Run Code Online (Sandbox Code Playgroud)

由此我假设容器中的PID 1如何映射到主机上的PID 17985,它也映射:

  • 容器中的PID 8到主机上的PID 18010,和
  • PID 9至PID 18011;
  • PID 10到PID 18012等等......

(这允许我从docker容器调试进程,使用仅在主机上可用的工具,而不是容器中的工具,如strace)

问题是我不知道假设pstree在容器和主机中以相同的顺序列出进程是多么安全.

如果有人能够建议一种更可靠的方法来检测Docker容器内运行的特定进程的主机上的PID,那将会很棒.

lar*_*sks 23

您可以查看该/proc/<pid>/status文件以确定命名空间PID和全局PID之间的映射.例如,如果在docker容器中我启动了几个sleep 900进程,如下所示:

# docker run --rm -it alpine sh
/ # sleep 900 &
/ # sleep 900 &
/ # sleep 900 &
Run Code Online (Sandbox Code Playgroud)

我可以看到它们在容器中运行:

/ # ps -fe
PID   USER     TIME   COMMAND
    1 root       0:00 sh
    7 root       0:00 sleep 900
    8 root       0:00 sleep 900
    9 root       0:00 sleep 900
   10 root       0:00 ps -fe
Run Code Online (Sandbox Code Playgroud)

我可以在主机上看一下这些:

# ps -fe | grep sleep
root     10394 10366  0 09:11 pts/10   00:00:00 sleep 900
root     10397 10366  0 09:12 pts/10   00:00:00 sleep 900
root     10398 10366  0 09:12 pts/10   00:00:00 sleep 900
Run Code Online (Sandbox Code Playgroud)

对于其中任何一个,我可以查看该status文件以查看名称空间pid:

# grep -i pid /proc/10394/status
Pid:    10394
PPid:   10366
TracerPid:  0
NSpid:  10394   7
Run Code Online (Sandbox Code Playgroud)

看一下这NSpid行,我可以看到在PID命名空间内这个进程有pid 7.事实上,如果我10394在主机上杀死进程:

# kill 10394
Run Code Online (Sandbox Code Playgroud)

然后在容器中我看到PID 7不再运行:

/ # ps -fe
PID   USER     TIME   COMMAND
    1 root       0:00 sh
    8 root       0:00 sleep 900
    9 root       0:00 sleep 900
   11 root       0:00 ps -fe
Run Code Online (Sandbox Code Playgroud)

  • 请注意,NSpid仅在Linux 4.1之后可用.所以这可能不适用于旧机器.作为替代方案,你可以通过docker exec'ing grep -l pid/proc/*/sched找到容器内的pid. (3认同)
  • 这是因为在 Mac 上,您在 Linux 虚拟机中运行 Docker。如果您要登录 Linux VM,您将看到此处描述的行为。 (3认同)
  • 看起来它解决了我的问题,遵循这个建议我可以用这个单行检索PID的完整映射:`for i in $(ps -ef | grep $(docker inspect --format'{{.State.Pid}} 'php-sandbox)| awk'{print $ 2}'); 做grep NSpid:/ proc/$ i/status; done` (2认同)