原文链接:https://fuckcloudnative.io/posts/find-kubernetes-pod-info-from-process-id/

在管理 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 名称,如果你的容器运行时是 containerdcrio,可以使用 crictl 来获取容器信息:

# 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"

使用 Go templatejq 都能获取 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'}
8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1

根据 Pod UID 找到 Service Account 的 token 挂载目录:

$ ll /var/lib/kubelet/pods/8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/volumes/kubernetes.io~secret/prometheus-k8s-token-p7bgb/

总用量 0
lrwxrwxrwx 1 root root 13 7月 10 21:24 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 7月 10 21:24 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 7月 10 21:24 token -> ..data/token

获取 token 信息:

$ export TOKEN=$(cat /var/lib/kubelet/pods/8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/volumes/kubernetes.io~secret/prometheus-k8s-token-p7bgb/token)

通过 curl 直接访问指标:

$ curl -s -H "Authorization: Bearer $TOKEN" --cacert /var/lib/kubelet/pods/8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/volumes/kubernetes.io~secret/prometheus-k8s-token-p7bgb/ca.crt --insecure https://127.0.0.1:10250/metrics/cadvisor

当然,如果你能找到集群管理员的证书、密钥和 CA 证书,也可以直接使用它们来访问,我就不展开说了。

5. 真奇技淫巧

最后再介绍一个思路清奇的方案,虽然有点小瑕疵,但思路很巧妙,大家可以借鉴一下。Kubernetes 创建的容器中的主机名对应的就是 Pod 名称,沿着这个思路,我们可以得到一个更巧妙的方法,通过 PID 的 uts namespace 来获得容器的主机名,进而就可以知道 Pod 名称,具体可以借助 nsenter 这个工具:

$ nsenter -t 14338 --uts hostname
prometheus-k8s-0

这么一看,确实比上面的方法优雅多了,但这个方法会有一点小问题,当容器使用 HostNetwork 模式运行时,hostname 是宿主机的 hostname,通过这种方法就得不到 Pod 名称。虽然不是通用的方法,但思路还是可以借鉴的,除了使用 nsenter 获取主机名外,还可以通过环境变量来获取,命令如下:

$ xargs -0 -L1 -a /proc/14338/environ | grep HOSTNAME
HOSTNAME=prometheus-k8s-0

解释一下这几个参数:

  • -0 : 表示使用 null 作为分隔符
  • -L : 表示指定多少行作为一个命令行参数。-L1 就表示指定 1 行作为命令行参数,即每一行分别运行一次命令。xargs 的作用就是将标准输入转换为命令行参数,如果 xargs 后面没有跟上真正要执行的命令,就表示使用默认的 echo。所以这里的 -L1 就表示分隔出来的每一行分别运行一次 echo 命令。
  • -a : 从文件中读取内容,而不是从标准输入读取。

如果你还不理解,好吧我尽力了。

最后再推荐一个项目,可以找到所有容器的 PID 以及对应的 Pod 信息,项目地址:pid2pod


Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12离线安装包发布地址http://store.lameleg.com ,欢迎体验。 使用了最新的sealos v3.3.6版本。 作了主机名解析配置优化,lvscare 挂载/lib/module解决开机启动ipvs加载问题, 修复lvscare社区netlink与3.10内核不兼容问题,sealos生成百年证书等特性。更多特性 https://github.com/fanux/sealos 。欢迎扫描下方的二维码加入钉钉群 ,钉钉群已经集成sealos的机器人实时可以看到sealos的动态。

Kubernetes 教程:根据 PID 获取 Pod 名称的更多相关文章

  1. Kubernetes家族容器小管家Pod在线答疑?

    Kubernetes家族容器小管家Pod在线答疑 不知道学习k8s的小伙伴们有没有跟我一样的疑问? k8s为什么不是直接运行容器,而是让Pod介入? Pod又是什么?为什么在应用容器化如此普遍的情况下 ...

  2. Atitit,通过pid获取进程文件路径 java php  c#.net版本大总结

    Atitit,通过pid获取进程文件路径 java php  c#.net版本大总结 1. 通过PID获取进程路径的几种方法2 1.1. GetModuleFileNameEx 想获得进程可执行文件的 ...

  3. Kubernetes中资源清单与Pod的生命周期(二)

    一.资源清单 1,定义: 在k8s中一般使用yaml格式的文件来创建符合我们预期的资源,这样的yaml被称为资源清单. 使用资源清单创建Pod: kubectl apply -f nginx.yaml ...

  4. Downward API —— 在容器内部获取 Pod 信息

    我们知道,每个 Pod 在被超过创建出来之后,都会被系统分配唯一的名字.IP地址,并且处于某个 Namespace 中,那么我们如何在 Pod 的容器内获取 Pod 的这些重要信息呢? 答案就是使用 ...

  5. Android 获取渠道名称

    直接看代码, //获取渠道名称public static String getChannelName(Activity ctx) { if (ctx == null) { return null; } ...

  6. 【转】 C# 小技巧之获取变量名称

    link: http://www.cnblogs.com/gongy/p/lm-2015-04-03.html 今天在自我规范程序设计的时候,变量名匹配字符串来自配置文件,网上找了一会儿发现也有朋友在 ...

  7. 通过PID获取进程路径的几种方法

    通过PID获取进程路径的几种方法 想获得进程可执行文件的路径最常用的方法是通过GetModuleFileNameEx函数获得可执行文件的模块路径这个函数从Windows NT 4.0开始到现在的Vis ...

  8. 根据UserAgent 获取操作系统名称

    /// <summary>        /// 根据 User Agent 获取操作系统名称        /// </summary>        private sta ...

  9. delphi根据进程PID获取程序所在路径的函数(用OpenProcess取得句柄,用GetModuleFileNameEx取得程序名)

    uses psapi; {根据进程PID获取程序所在路径的函数}function GetProcessExePath(PID: Cardinal): string;varpHandle: THandl ...

随机推荐

  1. 洛谷 P1991 【无线通讯网】

    这道题找到关键点那就是模板题了,代码好写哒~ 因为有S个电话,两个电话就可以连通两个块,那是不是我们就可以看做一条无消耗的边,提前连了起来.根据Kruskal的思想,我们每次加入最小的边,直到联通,由 ...

  2. jQuery创建表格并实现删除

    利用jQuery创建一个简单的表格,并添加一个简单的删除按钮 <!DOCTYPE html> <html lang="en"> <head> & ...

  3. QT Creator配置环境和安装

    原文链接:https://blog.csdn.net/qq_33154343/java/article/details/78587699 补充下其中缺少的步骤:安装后缺少QT GUI Applicat ...

  4. Python数据结构-树与树的遍历

    树:是一种抽象的数据类型 树的作用:用来模拟树状结构性质的数据集合 树的特点: 每个节点有零个或者多个节点 没有父节点的节点,叫做根节点 每一个根节点有且只有一个父节点 除了根节点外,每个节点可以分成 ...

  5. Python3笔记001 - 1.1 python概述

    第1章 认识python python语言特点 跨平台 开源的 解释型 面向对象 python语言的特点是:以对象为核心组织代码,支持多种编程范式,采用动态类型,自动进行内存回收,并能调用C语言库进行 ...

  6. 什么是electron

    Electron 是什么 定义 Electron是一个能让你使用传统前端技术(Nodejs, Javascript, HTML, CSS)开发一个跨平台桌面应用的框架.这里所说的桌面应用指的是在Win ...

  7. Jmeter(十六) - 从入门到精通 - JMeter前置处理器(详解教程)

    1.简介 前置处理器是在发出“取样器请求”之前执行一些操作.如果将前置处理器附加到取样器元件,则它将在该取样器元件运行之前执行.前置处理器最常用于在取样器请求运行前修改其设置,或更新未从响应文本中提取 ...

  8. CSS(六)- 内容布局 - Flexbox

    Flexbox是CSS3提供的用于布局的一套新属性,是为了应对行内块.浮动和表格格式产生的问题而生的.其包含针对容器(弹性容器,flex container)和针对其直接子元素(弹性项,flex it ...

  9. 主题博客添加 h5 贴边音乐插件

    前言: 前几日,在逛微博的时候,发现微博主页的左下角有一个贴边的音乐小插件,我顿时就想在自己博客上也弄一个玩玩.当时就想把微博那个移植过来,首先我用谷歌浏览器F12 查看页面源码,和检查元素代码,发现 ...

  10. java 数据结构(三):java常用类 三 日期时间API

    JDK 8之前日期时间API 1.获取系统当前时间:System类中的currentTimeMillis()long time = System.currentTimeMillis();//返回当前时 ...