从进程pid反推获得该进程所属容器

在生产环境中排查系统异常,经常会遇到某个进程异常,如D状态。此时我们需要找出这个进程所属哪个容器,以便找到对应的应用服务器进行排查。

通过procfs获取容器信息

通常我们使用 systemd-cgls 可以比较容易通过树形结构找出某个进程以及对应进程的容器,不过,在脚本中,其实还有一个办法,就是直接从 procfs 找出进程的 cgroup 来确定所属容器:

cat /proc/<process-pid>/cgroup

此时会看到所属cgroup的字符串,这个字符串就对应容器id,可以进一步获取容器名字:

docker inspect --format '{{.Name}}' "${containerId}" | sed 's/^\///'

反复查找ppid直到找到容器名

另一个思路是不断查找进程的父id,直到匹配上容器名特征,此时就能顺藤摸瓜找出容器:

获取docker的容器
#!/bin/bash

cpid=$1
while true; do
        ppid=$(ps -o ppid= -p $cpid)
        pname=$(ps -o comm= -p $ppid)
        if [ "$pname" == "docker" ]; then
                echo "$cpid parent $ppid ($pname)"
                break
        else
                echo "$cpid parent $ppid ($pname)"
                cpid=$ppid
        fi
done

docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.Name}}' | grep $cpid

类似思路,如果不是运行docker,而是使用 containerd运行时(runtime) ,则脚本修订:

获取containerd的容器
#!/bin/bash

cpid=$1
while true; do
        ppid=$(ps -o ppid= -p $cpid)
        pname=$(ps -o comm= -p $ppid)
        if [ "$pname" == "containerd-shim" ]; then
                echo "$cpid parent $ppid ($pname)"
                break
        else
                echo "$cpid parent $ppid ($pname)"
                cpid=$ppid
        fi
done

crictl ps -q | xargs crictl inspect --output go-template --template '{{.info.pid}}, {{.status.metadata.name}}' | grep $cpid

参考