前言
在管理 Kubernetes
集群的过程中,我们经常会遇到这样一种情况:在某台节点上发现某个进程资源占用量很高,却又不知道是哪个容器里的进程。有没有办法可以根据进程 PID
快速找到 Pod
名称呢?
解决
假设现在有一个 prometheus
进程的 PID
是 14338
:
要获取容器的 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
运行时为:containerd、crio
最后一步根据容器 ID
获取 Pod
名称,如果你的容器运行时是 containerd
或 crio
,可以使用 crictl
来获取容器信息:
# 使用 Go template 或 jq 都能获取 Pod 名称,看个人喜好。
# Go Template
$ crictl inspect -o go-template --template='{{index .status.labels "io.kubernetes.pod.name"}}' d6f24b62
prometheus-k8s-0
# jq
$ crictl inspect d6f24b62|jq '.status.labels["io.kubernetes.pod.name"]'
"prometheus-k8s-0"
运行时为:Docker
如果你的容器运行时是 Docker
,可以使用命令行工具 docker
来获取,方法和上面类似。
$ docker inspect d6f24b62 | jq '.[0].Config.Labels."io.kubernetes.pod.name"'
"prometheus-k8s-0"
一种特殊情况的处理,上面的方法适用于大多数场景。但有可能你的 cat /proc/14338/cgroup
输出的结果是这样的:
$ cat /proc/14338/cgroup
11:blkio:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/docker-d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
10:cpuset:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/docker-d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
9:freezer:/kubepods/burstable/pod8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/docker-d6f24b62ea28e9e67f7bc06f98de083cc49454f353389cd396f5d3ac6448f19c
......
这时你就需要将上面取容器 ID
的方法稍做修改:
$ cat /proc/d6f24b62/cgroup | awk -F '/' '{print $5}'|sed 's/docker-//g'
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
go script 脚本
package main
import (
"fmt"
"github.com/bitfield/script"
"log"
"os"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("请传递一个 PID 作为参数")
}
pid := os.Args[1]
data, err := script.File(fmt.Sprintf("/proc/%s/cgroup", pid)).Exec("awk -F '/' '{print $5}'").String()
if err != nil {
panic(err)
}
cid := data[7:19]
podName, err := script.Exec(fmt.Sprintf("docker inspect %s", cid)).JQ(".[0].Config.Labels.\"io.kubernetes.pod.name\"").String()
if err != nil {
panic(err)
}
fmt.Println(podName)
podNameSpace, err := script.Exec(fmt.Sprintf("docker inspect %s", cid)).JQ(".[0].Config.Labels.\"io.kubernetes.pod.namespace\"").String()
if err != nil {
panic(err)
}
fmt.Println(podNameSpace)
}
根据 Pid 获取 K8s Pod 名称,Shell 脚本
$ vim pod_name_info.sh
#!/usr/bin/env bash
Check_jq() {
which jq &> /dev/null
if [ $? != 0 ];then
echo -e "\033[32;32m 系统没有安装 jq 命令,请参考下面命令安装! \033[0m \n"
echo -e "\033[32;32m Centos 或者 RedHat 请使用命令 yum install jq -y 安装 \033[0m"
echo -e "\033[32;32m Ubuntu 或者 Debian 请使用命令 apt-get install jq -y 安装 \033[0m"
exit 1
fi
}
Pod_name_info() {
CID=`cat /proc/${pid}/cgroup | head -1 | awk -F '/' '{print $5}'`
CID=$(echo ${CID:0:8})
docker inspect $CID | jq '.[0].Config.Labels."io.kubernetes.pod.name"'
}
pid=$1
Check_jq
Pod_name_info
上面 Shell
脚本需要服务器上安装 jq
命令,因为脚本依赖 jq
来处理 json
格式。
简单介绍下 jq
jq
是一款命令行下处理 JSON 数据的工具
。其可以接受标准输入
,命令管道
或者文件中的 JSON 数据
,经过一系列的过滤器(filters
)和表达式的转后形成我们需要的数据结构并将结果输出到标准输出中。jq
的这种特性使我们可以很容易地在 Shell
脚本中调用它。
运行方式
# 通过 Pid 获取 Pod 名称
$ ./pod_name_info.sh Pid
根据 Pod 名称获取 Pid,Shell脚本
$ vim pod_pid_info.sh
#!/usr/bin/env bash
Check_jq() {
which jq &> /dev/null
if [ $? != 0 ];then
echo -e "\033[32;32m 系统没有安装 jq 命令,请参考下面命令安装! \033[0m \n"
echo -e "\033[32;32m Centos 或者 RedHat 请使用命令 yum install jq -y 安装 \033[0m"
echo -e "\033[32;32m Ubuntu 或者 Debian 请使用命令 apt-get install jq -y 安装 \033[0m"
exit 1
fi
}
Pid_info() {
docker_storage_location=`docker info | grep 'Docker Root Dir' | awk '{print $NF}'`
for docker_short_id in `docker ps | grep ${pod_name} | grep -v pause | awk '{print $1}'`
do
docker_long_id=`docker inspect ${docker_short_id} | jq ".[0].Id" | tr -d '"'`
cat ${docker_storage_location}/containers/${docker_long_id}/config.v2.json | jq ".State.Pid"
done
}
pod_name=$1
Check_jq
Pid_info
运行方式
# 通过 Pod名称 获取 Pid
$ ./pod_pid_info.sh Pod名称
巨人的肩膀
https://www.hi-linux.com/posts/1620.html
https://mp.weixin.qq.com/s/77v46oIraV22acC8eYqC5A
https://mp.weixin.qq.com/s/HF5rzr5fULiMWq1NPe780g