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

时间:2016-10-08 10:33:10

标签: linux docker process pid

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

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

# pstree -p 1
apache2(1)-+-apache2(8)
           |-apache2(9)
           |-apache2(10)
           |-apache2(11)
           |-apache2(12)
           `-apache2(20)

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

 $ docker inspect --format '{{.State.Pid}}' container
 17985

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

$ pstree -p 17985
apache2(17985)─┬─apache2(18010)
               ├─apache2(18011)
               ├─apache2(18012)
               ├─apache2(18013)
               ├─apache2(18014)
               └─apache2(18164)

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

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

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

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

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

2 个答案:

答案 0 :(得分:21)

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

# docker run --rm -it alpine sh
/ # sleep 900 &
/ # sleep 900 &
/ # sleep 900 &

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

/ # 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

我可以在主持人身上看到这些:

# 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

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

# grep -i pid /proc/10394/status
Pid:    10394
PPid:   10366
TracerPid:  0
NSpid:  10394   7

查看NSpid行,我可以看到PID名称空间中的进程有pid 7.事实上,如果我在主机上终止进程{​​{1}}:

10394

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

# kill 10394

答案 1 :(得分:0)

  • 调用docker sdk api ContainerList获取container_id映射docker镜像
  • 阅读/proc/<pid>/cgroup获取docker container_id
  • 您可以获取pid,container_id,docker镜像
func GetContainerID(pid int32) string {
    cgroupPath := fmt.Sprintf("/proc/%s/cgroup", strconv.Itoa(int(pid)))
    return getContainerID(cgroupPath)
}

func GetImage(containerId string) string {
    if containerId == "" {
        return ""
    }
    image, ok := containerImage[containerId]
    if ok {
        return image
    } else {
        return ""
    }
}
func getContainerID(cgroupPath string) string {
    containerID := ""
    content, err := ioutil.ReadFile(cgroupPath)
    if err != nil {
        return containerID
    }
    lines := strings.Split(string(content), "\n")
    for _, line := range lines {
        field := strings.Split(line, ":")
        if len(field) < 3 {
            continue
        }
        cgroup_path := field[2]
        if len(cgroup_path) < 64 {
            continue
        }
        // Non-systemd Docker
        //5:net_prio,net_cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
        //3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
        pos := strings.LastIndex(cgroup_path, "/")
        if pos > 0 {
            id_len := len(cgroup_path) - pos - 1
            if id_len == 64 {
                //p.InDocker = true
                // docker id
                containerID = cgroup_path[pos+1 : pos+1+64]
                // logs.Debug("pid:%v in docker id:%v", pid, id)
                return containerID
            }
        }
        // systemd Docker
        //5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
        docker_str := "docker-"
        pos = strings.Index(cgroup_path, docker_str)
        if pos > 0 {
            pos_scope := strings.Index(cgroup_path, ".scope")
            id_len := pos_scope - pos - len(docker_str)
            if pos_scope > 0 && id_len == 64 {
                containerID = cgroup_path[pos+len(docker_str) : pos+len(docker_str)+64]
                return containerID
            }
        }
    }
    return containerID
}

The golang code with get the pid container