1. 程式人生 > >Kubernetes 教程:根據 PID 獲取 Pod 名稱

Kubernetes 教程:根據 PID 獲取 Pod 名稱

> 原文連結:[https://fuckcloudnative.io/posts/find-kubernetes-pod-info-from-process-id/](https://fuckcloudnative.io/posts/find-kubernetes-pod-info-from-process-id/) 在管理 `Kubernetes` 叢集的過程中,我們經常會遇到這樣一種情況:在某臺節點上發現某個程序資源佔用量很高,卻又不知道是哪個容器裡的程序。有沒有辦法可以根據 `PID` 快速找到 `Pod` 名稱呢? 假設現在有一個 prometheus 程序的 PID 是 `14338`: ![](https://img2020.cnblogs.com/other/1737323/202007/1737323-20200727103638309-1041491547.png) 為了進一步挖掘資訊,有兩種思路,一種是挖掘 `PID` 對應的容器的資訊,另一種是挖掘 PID 對應的 `Pod` 的資訊。 ## 1. Container ID 要獲取容器的 ID,可以檢視 PID 對應的 `cgroup` 資訊: ```bash $ 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: ```bash $ CID=$(cat /proc/14338/cgroup | awk -F '/' '{print $5}') $ echo ${CID:0:8} d6f24b62 ``` 最後一步根據容器 ID 獲取 Pod 名稱,如果你的容器執行時是 `containerd` 或 `crio`,可以使用 `crictl` 來獲取容器資訊: ```bash # 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 template` 或 `jq` 都能獲取 Pod 名稱,看個人喜好。 如果你的容器執行時是 Docker,可以使用命令列工具 `docker` 來獲取,方法和上面類似。 ## 2. Pod UID 下面來看看第二種方法,先根據 PID 直接獲取 `Pod UID`: ```bash $ cat /proc/14338/mountinfo | grep "etc-hosts" | awk -F / {'print $6'} 8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1 ``` 然後根據 Pod UID 獲取 Pod 名稱: ```bash $ 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): ```bash 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 } ``` 執行下面的命令使修改立即生效: ```bash $ source ~/.bashrc ``` 然後就可以使用該函式來獲取 Pod 名稱啦: ```bash $ podinfo 14338 prometheus-k8s-0 ``` ## 4. 舉一反三 這個思路也可以用來解決其他問題,大家要學會舉一反三,我舉個例子。Kubernetes 中的很多元件都是通過 `HTTPS` 協議來暴露指標,比如 `kubelet`,那麼如何使用 API 來訪問這些指標呢? 先選取一個容器,比如 `prometheus`,找到它的 PID: ```bash $ 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: ```bash $ cat /proc/14338/mountinfo | grep "etc-hosts" | awk -F / {'print $6'} 8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1 ``` 根據 Pod UID 找到 `Service Account` 的 token 掛載目錄: ```bash $ 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 資訊: ```bash $ export TOKEN=$(cat /var/lib/kubelet/pods/8e018a8e-4aaa-4ac6-986a-1a5133a4bcf1/volumes/kubernetes.io~secret/prometheus-k8s-token-p7bgb/token) ``` 通過 curl 直接訪問指標: ```bash $ 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` 這個工具: ```bash $ nsenter -t 14338 --uts hostname prometheus-k8s-0 ``` 這麼一看,確實比上面的方法優雅多了,但這個方法會有一點小問題,當容器使用 `HostNetwork` 模式執行時,hostname 是宿主機的 hostname,通過這種方法就得不到 Pod 名稱。雖然不是通用的方法,但思路還是可以借鑑的,除了使用 `nsenter` 獲取主機名外,還可以通過環境變數來獲取,命令如下: ```bash $ 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](https://github.com/heptiolabs/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的動態。 ![](https://img2020.cnblogs.com/other/1737323/202007/1737323-20200727103638518-1191734