Skip to content

通过进程pid查询对应docker容器信息

1. 一般获取方法

我们都知道Docker容器的哲学是一个Docker容器只运行一个进程。在这种情况下,我们可以很容器找到进程和容器的对应关系。

如,我们在进程中发现有一个redis-server的程序:

sh
[root@docker ~]# ps -ef|grep -v grep|grep redis
polkitd  17942 17923  0 22:36 ?        00:00:03 redis-server *:6379

可以知道,其进程PID是17942

1.1 通过docker top命令查看

当我们服务器上面运行的容器不多时,可以直接使用这种方式查看:

sh
# 查看运行的容器
[root@docker ~]# docker ps
CONTAINER ID   IMAGE                     COMMAND                  CREATED          STATUS             PORTS                    NAMES
77e8f1f47d09   meizhaohui/testimage:v1   "/bin/bash /root/run…"   22 minutes ago   Up 22 minutes                               wizardly_carson
80bbd285db0b   sonatype/nexus3:3.59.0    "/opt/sonatype/nexus…"   2 weeks ago      Up 2 weeks         0.0.0.0:8081->8081/tcp   nexus
790a0902c364   e0ce02f88e58              "docker-entrypoint.s…"   4 weeks ago      Up About an hour   0.0.0.0:6375->6379/tcp   redis-6375
[root@docker ~]#

可以看到,也就三个容器,直接docker top分别查看三个容器运行的进程信息即可:

sh
[root@docker ~]# docker top wizardly_carson
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                5229                29140               0                   23:45               pts/0               00:00:00            sleep 1
root                29140               29120               0                   23:19               pts/0               00:00:00            /bin/bash /root/run.sh /bin/bash
root                29181               29140               0                   23:19               pts/0               00:00:00            ping baidu.com -c 10000
root                29182               29140               0                   23:19               pts/0               00:00:00            ping baidu.com -c 10000
[root@docker ~]# docker top nexus
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
200                 5265                5245                0                   Aug21               ?                   02:36:11            /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.382.b05-2.el8.x86_64/jre/bin/java -server -Dinstall4j.jvmDir=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.382.b05-2.el8.x86_64/jre -Dexe4j.moduleName=/opt/sonatype/nexus/bin/nexus -XX:+UnlockDiagnosticVMOptions -Dinstall4j.launcherId=245 -Dinstall4j.swt=false -Di4jv=0 -Di4jv=0 -Di4jv=0 -Di4jv=0 -Di4jv=0 -Xms2703m -Xmx2703m -XX:MaxDirectMemorySize=2703m -Djava.util.prefs.userRoot=/nexus-data/javaprefs -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=../sonatype-work/nexus3/log/jvm.log -XX:-OmitStackTraceInFastThrow -Djava.net.preferIPv4Stack=true -Dkaraf.home=. -Dkaraf.base=. -Dkaraf.etc=etc/karaf -Djava.util.logging.config.file=etc/karaf/java.util.logging.properties -Dkaraf.data=../sonatype-work/nexus3 -Dkaraf.log=../sonatype-work/nexus3/log -Djava.io.tmpdir=../sonatype-work/nexus3/tmp -Dkaraf.startLocalConsole=false -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=lib/endorsed -Di4j.vpt=true -classpath /opt/sonatype/nexus/.install4j/i4jruntime.jar:/opt/sonatype/nexus/lib/boot/nexus-main.jar:/opt/sonatype/nexus/lib/boot/activation-1.1.1.jar:/opt/sonatype/nexus/lib/boot/jakarta.xml.bind-api-2.3.3.jar:/opt/sonatype/nexus/lib/boot/jaxb-runtime-2.3.3.jar:/opt/sonatype/nexus/lib/boot/txw2-2.3.3.jar:/opt/sonatype/nexus/lib/boot/istack-commons-runtime-3.0.10.jar:/opt/sonatype/nexus/lib/boot/org.apache.karaf.main-4.3.9.jar:/opt/sonatype/nexus/lib/boot/osgi.core-7.0.0.jar:/opt/sonatype/nexus/lib/boot/org.apache.karaf.specs.activator-4.3.9.jar:/opt/sonatype/nexus/lib/boot/org.apache.karaf.diagnostic.boot-4.3.9.jar:/opt/sonatype/nexus/lib/boot/org.apache.karaf.jaas.boot-4.3.9.jar com.install4j.runtime.launcher.UnixLauncher run 9d17dc87 0 0 org.sonatype.nexus.karaf.NexusMain
[root@docker ~]# docker top redis-6375
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
polkitd             17942               17923               0                   22:36               ?                   00:00:03            redis-server *:6379
[root@docker ~]#

可以看到最后一个容器redis-6375的PID是17942,刚好与我们要查找到redis进程17942相同。这样就找到了进程对应的容器名称,也是知道了容器信息了。

1.2 通过docker inspect命令查看

通过docker inspect可以获取容器的远数据信息。

我们可以通过依次检查三个运行的容器的元数据信息:

sh
[root@docker ~]# docker inspect wizardly_carson|jq '.[0].State'
{
  "Status": "running",
  "Running": true,
  "Paused": false,
  "Restarting": false,
  "OOMKilled": false,
  "Dead": false,
  "Pid": 29140,
  "ExitCode": 0,
  "Error": "",
  "StartedAt": "2023-09-09T15:19:01.819911076Z",
  "FinishedAt": "0001-01-01T00:00:00Z"
}
[root@docker ~]# docker inspect wizardly_carson|jq '.[0].State.Pid'
29140
[root@docker ~]# docker inspect nexus|jq '.[0].State.Pid'
5265
[root@docker ~]# docker inspect redis-6375|jq '.[0].State.Pid'
17942
[root@docker ~]#

运行效果图:

1.3 通过ps命令查看

通过man ps可以看到有这样的帮助信息:

sh
To see every process with a user-defined format:
          ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm
          ps axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
          ps -Ao pid,tt,user,fname,tmout,f,wchan

我们使用ps -eo命令来输出指定样式的结果。

我们主要使用pidcgroup信息:

sh
[root@docker ~]# ps -eo 'pid,cgroup'|grep -v grep |grep 17942
17942 11:blkio:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,10:pids:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,9:devices:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,8:freezer:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,7:cpuset:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,6:perf_event:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,5:memory:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,4:hugetlb:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,3:cpuacct,cpu:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,2:net_prio,net_cls:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095,1:name=systemd:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095

查询出的结果中包含有docker容器的id值相关的信息,如以上结果中/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095字符串中790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095就是容器的长ID信息。

再通过docker ps反查容器ID对应的容器信息:

sh
[root@docker ~]# docker ps --no-trunc|grep 790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095   sha256:e0ce02f88e589621ae0c99073142b587c1bbe3cfbab70b484e7af700d7057e0e   "docker-entrypoint.sh redis-server"   4 weeks ago      Up About an hour   0.0.0.0:6375->6379/tcp   redis-6375

这样也获取到了进程对应的容器是redis-6375

1.4 查看进程/proc/$PID/cgroup文件

如进程变量PID=17942,直接查看/proc/$PID/cgroup文件内容:

sh
[root@docker ~]# PID=17942
[root@docker ~]# cat /proc/$PID/cgroup
11:blkio:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
10:pids:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
9:devices:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
8:freezer:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
7:cpuset:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
6:perf_event:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
5:memory:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
4:hugetlb:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
3:cpuacct,cpu:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
2:net_prio,net_cls:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
1:name=systemd:/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095
[root@docker ~]#

也可以知道进程对应的容器长ID是790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095。像上节一样使用docker ps --no-trunc命令也可以查到对应容器是redis-6375

1.5 异常容器示例

我们都知道Docker容器的哲学是一个Docker容器只运行一个进程,但是有时候我们就是需要在一个Docker容器中运行多个进程。也就有可能容器进程创建了新的子进程。

就像我们运行的wizardly_carson容器一样:

sh
[root@docker ~]# docker top wizardly_carson
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                13132               29140               0                   00:11               pts/0               00:00:00            sleep 1
root                29140               29120               0                   Sep09               pts/0               00:00:00            /bin/bash /root/run.sh /bin/bash
root                29181               29140               0                   Sep09               pts/0               00:00:00            ping baidu.com -c 10000
root                29182               29140               0                   Sep09               pts/0               00:00:00            ping baidu.com -c 10000
[root@docker ~]# docker top wizardly_carson
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                13176               29140               0                   00:11               pts/0               00:00:00            sleep 1
root                29140               29120               0                   Sep09               pts/0               00:00:00            /bin/bash /root/run.sh /bin/bash
root                29181               29140               0                   Sep09               pts/0               00:00:00            ping baidu.com -c 10000
root                29182               29140               0                   Sep09               pts/0               00:00:00            ping baidu.com -c 10000
[root@docker ~]#

如我们的两个长ping进程ping baidu.com -c 10000,一个是29181,另一个是29182,都是容器进程29140的子进程。

这个时候我们如果想知道29181是哪个容器的进程,则使用上述1.1-1.4节的方法可能有点难以确认。

docker top就不试了,因为我们是从docker top wizardly_carson看到进程29181是个子进程。

我们尝试一下其他方法:

sh
[root@docker ~]# docker inspect wizardly_carson|jq '.[0].State.Pid'
29140
[root@docker ~]# docker inspect wizardly_carson|jq|grep 29181
[root@docker ~]# docker inspect nexus|jq '.[0].State.Pid'
5265
[root@docker ~]# docker inspect redis-6375|jq '.[0].State.Pid'
17942
[root@docker ~]#

直接通过docker inspect未能获取到子进程信息。

sh
[root@docker ~]# ps -eo 'pid,cgroup'|grep -v grep |grep 29181
29181 11:blkio:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,10:pids:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,9:devices:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,8:freezer:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,7:cpuset:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,6:perf_event:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,5:memory:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,4:hugetlb:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,3:cpuacct,cpu:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,2:net_prio,net_cls:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15,1:name=systemd:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15

通过ps查看cgroup信息获取到容器长ID信息。

sh
[root@docker ~]# PID=29181
[root@docker ~]# cat /proc/$PID/cgroup
11:blkio:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
10:pids:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
9:devices:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
8:freezer:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
7:cpuset:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
6:perf_event:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
5:memory:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
4:hugetlb:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
3:cpuacct,cpu:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
2:net_prio,net_cls:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
1:name=systemd:/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15
[root@docker ~]#

直接查看/proc/$PID/cgroup文件内容也获取到了。

2. 终极获取方法

可以直接在/sys/fs/cgroup/memory/docker目录下搜索cgroup.procs文件,该文件会记录每个容器对应的Pid和子进程Pid信息。

查看目录下的文件列表信息:

sh
[root@docker ~]# ls /sys/fs/cgroup/memory/docker
77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15  memory.kmem.tcp.failcnt             memory.numa_stat
790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095  memory.kmem.tcp.limit_in_bytes      memory.oom_control
80bbd285db0bc84a50b785a2aeb688d8bf6879e5fa1381357fa1426a9f38148a  memory.kmem.tcp.max_usage_in_bytes  memory.pressure_level
cgroup.clone_children                                             memory.kmem.tcp.usage_in_bytes      memory.soft_limit_in_bytes
cgroup.event_control                                              memory.kmem.usage_in_bytes          memory.stat
cgroup.procs                                                      memory.limit_in_bytes               memory.swappiness
memory.failcnt                                                    memory.max_usage_in_bytes           memory.usage_in_bytes
memory.force_empty                                                memory.memsw.failcnt                memory.use_hierarchy
memory.kmem.failcnt                                               memory.memsw.limit_in_bytes         notify_on_release
memory.kmem.limit_in_bytes                                        memory.memsw.max_usage_in_bytes     tasks
memory.kmem.max_usage_in_bytes                                    memory.memsw.usage_in_bytes
memory.kmem.slabinfo                                              memory.move_charge_at_immigrate
[root@docker ~]#

查找cgroup.procs文件:

sh
[root@docker ~]# find /sys/fs/cgroup/memory/docker -name 'cgroup.procs'
/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs
/sys/fs/cgroup/memory/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095/cgroup.procs
/sys/fs/cgroup/memory/docker/80bbd285db0bc84a50b785a2aeb688d8bf6879e5fa1381357fa1426a9f38148a/cgroup.procs
/sys/fs/cgroup/memory/docker/cgroup.procs

查找cgroup.procs文件,然后在查找到的文件中搜索我们想匹配的进程29181:

sh
[root@docker ~]# find /sys/fs/cgroup/memory/docker -name 'cgroup.procs'|xargs grep --color=always 29181
/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs:29181
[root@docker ~]#

可以看到,在文件/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs中匹配到了该进程。

使用该方法,可以随意匹配任意容器进程或其子进程,然后通过文件路径确定容器的长ID值。

编写快捷命令:

sh
alias gcbp='get_container_by_pid'
# 通过进程PID查询容器信息
function get_container_by_pid() {
    pid=$1
    find /sys/fs/cgroup/memory/docker -name 'cgroup.procs'|xargs grep --color=always "${pid}"
    container_id=$(find /sys/fs/cgroup/memory/docker -name 'cgroup.procs'|xargs grep "${pid}"|awk -F'/' '{print $7}'|cut -c1-12)
    if [[ -n "${container_id}" ]]; then
    	docker ps|head -n 1 ; docker ps |grep --color=always "${container_id}"
    else
    	echo "进程 ${pid} 不在任何一个容器中,请检查"
    fi
}

将以上信息存放到~/.bashrc文件中,然后使用source ~/.bashrc加载配置。

然后进行测试:

sh
# 查看wizardly_carson容器的PID,可以看到能够匹配到容器信息
[root@docker ~]# gcbp 29140
/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs:29140
CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                    NAMES
77e8f1f47d09   meizhaohui/testimage:v1   "/bin/bash /root/run…"   2 hours ago   Up 2 hours                            wizardly_carson

# 查看wizardly_carson容器子进程的PID,可以看到能够匹配到容器信息
[root@docker ~]# gcbp 29181
/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs:29181
CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                    NAMES
77e8f1f47d09   meizhaohui/testimage:v1   "/bin/bash /root/run…"   2 hours ago   Up 2 hours                            wizardly_carson

# 查看wizardly_carson容器子进程的PID,可以看到能够匹配到容器信息
[root@docker ~]# gcbp 29182
/sys/fs/cgroup/memory/docker/77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15/cgroup.procs:29182
CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                    NAMES
77e8f1f47d09   meizhaohui/testimage:v1   "/bin/bash /root/run…"   2 hours ago   Up 2 hours                            wizardly_carson

# 查看nexus容器的进程,可以看到能够匹配到容器信息
[root@docker ~]# gcbp 5265
/sys/fs/cgroup/memory/docker/80bbd285db0bc84a50b785a2aeb688d8bf6879e5fa1381357fa1426a9f38148a/cgroup.procs:5265
CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                    NAMES
80bbd285db0b   sonatype/nexus3:3.59.0    "/opt/sonatype/nexus…"   2 weeks ago   Up 2 weeks   0.0.0.0:8081->8081/tcp   nexus

# 查看redis-6375容器的进程,可以看到能够匹配到容器信息
[root@docker ~]# gcbp 17942
/sys/fs/cgroup/memory/docker/790a0902c36417b1388820b59d9156181d718a327bb6fa09880c4568fdd07095/cgroup.procs:17942
CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                    NAMES
790a0902c364   e0ce02f88e58              "docker-entrypoint.s…"   4 weeks ago   Up 2 hours   0.0.0.0:6375->6379/tcp   redis-6375

# 查看containerd-shim-runc-v2进程,可以看到未能匹配到容器信息
[root@docker ~]# gcbp 29120
进程 29120 不在任何一个容器中,请检查
[root@docker ~]# ps -ef|grep -v grep|grep 29120
root     29120     1  0 Sep09 ?        00:00:04 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 77e8f1f47d093f6136e7a7bdf65ac3b87974922a200b2ce05a551cc6485d6d15 -address /run/containerd/containerd.sock
root     29140 29120  0 Sep09 pts/0    00:00:01 /bin/bash /root/run.sh /bin/bash
[root@docker ~]#

到此,可以看到,最后的快捷命令可以通用上,匹配上容器进程或容器子进程,不在容器中的进程也给出提示。

参考:

本首页参考 https://notes.fe-mm.com/ 配置而成