从进程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