根据 PID 获取容器所在的 Pod 名称
想获得更好的阅读体验,可以点击『阅读原文』直接访问博客链接。
在管理
Kubernetes
集群的过程中,我们经常会遇到这样一种情况:在某台节点上发现某个进程资源占用量很高,却又不知道是哪个容器里的进程。有没有办法可以根据
PID
快速找到
Pod
名称呢?
假设现在有一个 prometheus 进程的 PID 是
14338
:
为了进一步挖掘信息,有两种思路,一种是挖掘
PID
对应的容器的信息,另一种是挖掘 PID 对应的
Pod
的信息。
1. Container ID
要获取容器的 ID,可以查看 PID 对应的
cgroup
信息:
$ cat /proc/14338/cgroup
11:blkio:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
10:cpuset:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
9:freezer:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
8:hugetlb:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
7:perf_event:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
6:cpuacct,cpu:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
5:pids:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
4:devices:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
3:net_prio,net_cls:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
2:memory:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
1:name=systemd:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
可以看到该进程对应的容器 ID 为
d6f24b62...
,可以再优化一下上面的命令,直接获取容器 ID:
$ CID=$(cat /proc/14338/cgroup | awk -F '/' '{print $5}')
$ echo ${CID:0:8}
d6f24b62
最后一步根据容器 ID 获取 Pod 名称,如果你的容器运行时是
containerd
或
crio
,可以使用
crictl
来获取容器信息:
# Go Template
$ crictl inspect -o go-template --template='{{index .status.labels "io.kubernetes.pod.name"}}' d6f24b62
prometheus-k8s-0
$ crictl inspect d6f24b62|jq '.status.labels["io.kubernetes.pod.name"]'
"prometheus-k8s-0"
使用
Go template
或
jq
都能获取 Pod 名称,看个人喜好。
如果你的容器运行时是 Docker,可以使用命令行工具
docker
来获取,方法和上面类似。
2. Pod UID
下面来看看第二种方法,先根据 PID 直接获取
Pod UID
:
$ cat /proc/14338/mountinfo | grep "etc-hosts" | awk -F / {'print $6'}
8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1
然后根据 Pod UID 获取 Pod 名称:
$ crictl ps -o json | jq '.[][].labels | select (.["io.kubernetes.pod.uid"] == "8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1") | .["io.kubernetes.pod.name"]'|uniq
"prometheus-k8s-0"
3. 整合
方法是有了,怎么才能将所有的步骤合并成一个步骤,一步到位获取 Pod 名称呢?可以在
~/.bashrc
中添加一个
shell
函数,选择上面的方法 1,并使用 go template 来格式化(你也可以使用上面提到的其他方法,但需要安装 jq):
podinfo() {
CID=$(cat /proc/$1/cgroup | awk -F '/' '{print $5}')
CID=$(echo ${CID:0:8})
crictl inspect -o go-template --template='{{index .status.labels "io.kubernetes.pod.name"}}' $CID
}
执行下面的命令使修改立即生效:
$ source ~/.bashrc
然后就可以使用该函数来获取 Pod 名称啦:
$ podinfo 14338
prometheus-k8s-0
4. 举一反三
这个思路也可以用来解决其他问题,大家要学会举一反三,我举个例子。Kubernetes 中的很多组件都是通过
HTTPS
协议来暴露指标,比如
kubelet
,那么如何使用 API 来访问这些指标呢?
先选取一个容器,比如
prometheus
,找到它的 PID:
$ ps -ef|grep "/bin/prometheus"
1000 14338 14246 4 7月10 ? 04:29:02 /bin/prometheus --web.console.templates=/etc/prometheus/consoles --web.console.libraries=/etc/prometheus/console_libraries --config.file=/etc/prometheus/config_out/prometheus.env.yaml --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=24h --web.enable-lifecycle --storage.tsdb.no-lockfile --web.route-prefix=/
1000 14402 14246 0 7月10 ? 00:00:10 /bin/prometheus-config-reloader --log-format=logfmt --reload-url=http://localhost:9090/-/reload --config-file=/etc/prometheus/config/prometheus.yaml.gz --config-envsubst-file=/etc/prometheus/config_out/prometheus.env.yaml
root 15956 555 0 18:19 pts/0 00:00:00 grep --color=auto /bin/prometheus
根据 PID 找到 Pod UID:
$ cat /proc/14338/mountinfo | grep "etc-hosts" | awk -F / {'print $6'}