kubectl top 命令解析

2021-12-22 k8s技術圈

原文連結:http://www.xuyasong.com/?p=1781

一. 前言

kubectl top 可以很方便地查看node、pod 的實時資源使用情況:如CPU、內存。這篇文章會介紹其數據鏈路和實現原理,同時借 kubectl top 闡述 k8s 中的監控體系,窺一斑而知全豹。最後會解釋常見的一些問題:

kubectl top 為什麼會報錯?

kubectl top node 怎麼計算,和節點上直接 top 有什麼區別?

kubectl top pod 怎麼計算,包含 pause 嗎?

kubectl top pod 和exec 進入 pod 後看到的 top 不一樣?

kubectl top pod 和 docker stats得到的值為什麼不同?

以下命令的運行環境為:

二. 使用

kubectl top 是基礎命令,但是需要部署配套的組件才能獲取到監控值

1.8以下:部署 heapter

1.8以上:部署 metric-server

kubectl top node: 查看node的使用情況

kubectl top pod: 查看 pod 的使用情況

不指定pod 名稱,則顯示命名空間下所有 pod,–containers可以顯示 pod 內所有的container

指標含義:

和 k8s中 的 request、limit 一致,CPU單位100m=0.1 內存單位1Mi=1024Ki

pod 的內存值是其實際使用量,也是做 limit 限制時判斷 oom 的依據。pod的使用量等於其所有業務容器的總和,不包括 pause 容器,值等於 cadvisr中的 container_memory_working_set_bytes 指標

node 的值並不等於該 node 上所有 pod 值的總和,也不等於直接在機器上運行 top 或 free 看到的值

三. 實現原理3.1 數據鏈路

kubectl top 、 k8s dashboard 以及 HPA 等調度組件使用的數據是一樣,數據鏈路如下:

使用 heapster 時:apiserver 會直接將 metric 請求通過 proxy 的方式轉發給集群內的 hepaster 服務。

而使用 metrics-server 時:apiserver 是通過 /apis/metrics.k8s.io/ 的地址訪問 metric

這裡可以對比下 kubect get pod 時的日誌:

3.2 metric api

可以發現,heapster 使用的是 proxy 轉發,而 metric-server 和普通 pod都是使用 api/xx 的資源接口,heapster採用的這種 proxy 方式是有問題的:

proxy 只是代理請求,一般用於問題排查,不夠穩定,且版本不可控

heapster 的接口不能像 apiserver 一樣有完整的鑑權以及 client 集成,兩邊都維護的話代價高,如 generic apiserver

pod 的監控數據是核心指標(HPA調度),應該和 pod 本身擁有同等地位,即 metric 應該作為一種資源存在,如 metrics.k8s.io 的形式,稱之為 Metric Api

於是官方從 1.8 版本開始逐步廢棄 heapster,並提出了上邊 Metric api 的概念,而 metrics-server 就是這種概念下官方的一種實現,用於從 kubelet獲取指標,替換掉之前的 heapster

3.3 kube-aggregator

有了 metrics-server 組件,採集到了需要的數據,也暴露了接口,但走到這一步和 heapster 其實沒有區別,最關鍵的一步就是如何將打到 apiserver的 /apis/metrics.k8s.io 請求轉發給 metrics-server 組件?解決方案就是:kube-aggregator

kube-aggregator 是對 apiserver 的有力擴展,它允許 k8s 的開發人員編寫一個自己的服務,並把這個服務註冊到 k8s 的 api 裡面,即擴展 API,metric-server 其實在 1.7版本就已經完成了,只是在等 kube-aggregator 的出現。

kube-aggregator 是 apiserver 中的實現,有些 k8s 版本默認沒開啟,你可以加上這些配置來開啟,他的核心功能是動態註冊、發現匯總、安全代理

如 metric-server 註冊 pod 和 node 時:

3.4 監控體系

在提出 metric api 的概念時,官方也提出了新的監控體系,監控資源被分為了2種:

核心指標只包含 node 和 pod 的 cpu、內存等,一般來說,核心指標作 HPA 已經足夠,但如果想根據自定義指標:如請求 qps/5xx 錯誤數來實現 HPA,就需要使用自定義指標了。

目前 Kubernetes 中自定義指標一般由 Prometheus 來提供,再利用 k8s-prometheus-adpater 聚合到 apiserver,實現和核心指標同樣的效果。

3.5 kubelet

前面提到,無論是 heapster 還是 metric-server,都只是數據的中轉和聚合,兩者都是調用的 kubelet 的 api 接口獲取的數據,而 kubelet 代碼中實際採集指標的是 cadvisor 模塊,你可以在 node 節點訪問 10255 埠(1.11版本過後是10250埠)獲取監控數據:

示例,容器的內存使用量:

Kubelet 雖然提供了 metric 接口,但實際監控邏輯由內置的 cAdvisor 模塊負責,演變過程如下:

從k8s 1.6開始,kubernetes 將 cAdvisor 開始集成在kubelet中,不需要單獨配置

從k8s 1.7開始,Kubelet metrics API 不再包含 cadvisor metrics,而是提供了一個獨立的 API 接口來做匯總

從 k8s 1.12 開始,cadvisor 監聽的埠在k8s中被刪除,所有監控數據統一由 Kubelet 的 API 提供

到這裡為止,k8s 範圍內的監控體系就結束了。

3.6 cadvisor

cadvisor 由谷歌開源,使用 Go 開發,cadvisor 不僅可以搜集一臺機器上所有運行的容器信息,包括 CPU 使用情況、內存使用情況、網絡吞吐量及文件系統使用情況,還提供基礎查詢界面和 http 接口,方便其他組件進行數據抓取。在K8S 中集成在 Kubelet 裡作為默認啟動項,k8s 官方標配。

cadvisor 拿到的數據結構示例:

核心邏輯是通過 new 出來的 memoryStorage 以及 sysfs 實例,創建一個manager 實例,manager 的 interface 中定義了許多用於獲取容器和 machine 信息的函數

cadvisor的指標解讀:cgroup-v1(https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)

cadvisor 獲取指標時實際調用的是 runc/libcontainer 庫,而 libcontainer 是對 cgroup 文件 的封裝,即 cadvsior 也只是個轉發者,它的數據來自於cgroup 文件。

3.7 cgroup

cgroup 文件中的值是監控數據的最終來源,如

mem usage 的值,來自於
/sys/fs/cgroup/memory/docker/[containerId]/memory.usage_in_bytes

如果沒限制內存,Limit=machine_mem,否則來自於
/sys/fs/cgroup/memory/docker/[id]/memory.limit_in_bytes

內存使用率=memory.usage_in_bytes/memory.limit_in_bytes

一般情況下,cgroup文件夾下的內容包括CPU、內存、磁碟、網絡等信息:


如 memory 下的幾個常用的指標含義:

memory.stat 中的信息是最全的:

原理到這裡結束,這裡解釋下最開始的 kubectl top 的幾個問題:

四. 問題4.1 kubectl top 為什麼會報錯

一般情況下 top 報錯有以下幾種,可以 kubectl top pod -v=10看到具體的調用日誌:

沒有部署 heapster 或者 metric-server,或者 pod 運行異常,可以排查對應 pod 日誌

要看的 pod 剛剛建出來,還沒來得及採集指標,報 not found 錯誤,默認 1 分鐘

以上兩種都不是,可以檢查下 kubelet 的 10255 埠是否開放,默認情況下會使用這個只讀埠獲取指標,也可以在 heapster 或 metric-server 的配置中增加證書,換成 10250 認證埠

4.2 kubectl top pod 內存怎麼計算,包含 pause容器嗎

每次啟動 pod,都會有一個 pause 容器,既然是容器就一定有資源消耗(一般在 2-3M 的內存),cgroup 文件中,業務容器和 pause 容器都在同一個 pod的文件夾下。

但 cadvisor 在查詢 pod 的內存使用量時,是先獲取了 pod 下的container列表,再逐個獲取container的內存佔用,不過這裡的 container 列表並沒有包含 pause,因此最終 top pod 的結果也不包含 pause 容器

pod 的內存使用量計算

kubectl top pod 得到的內存使用量,並不是 cadvisor 中的 container_memory_usage_bytes,而是 container_memory_working_set_bytes,計算方式為:

container_memory_working_set_bytes 是容器真實使用的內存量,也是 limit限制時的 oom 判斷依據。

cadvisor 中的 container_memory_usage_bytes 對應 cgroup 中的 memory.usage_in_bytes 文件,但 container_memory_working_set_bytes 並沒有具體的文件,他的計算邏輯在 cadvisor 的代碼中,如下:

同理,node 的內存使用量也是 container_memory_working_set_bytes。

4.3 kubectl top node 怎麼計算,和節點上直接 top 有什麼區別

kubectl top node 得到的 cpu 和內存值,並不是節點上所有 pod 的總和,不要直接相加。top node 是機器上 cgroup 根目錄下的匯總統計

在機器上直接 top 命令看到的值和 kubectl top node 不能直接對比,因為計算邏輯不同,如內存,大致的對應關係是(前者是機器上 top,後者是 kubectl top):

rss + cache = (in)active_anon + (in)active_file


4.4 kubectl top pod 和 exec 進入 pod 後看到的 top 不一樣

top 命令的差異和上邊一致,無法直接對比,同時,就算你對 pod 做了 limit 限制,pod 內的 top 看到的內存和 cpu 總量仍然是機器總量,並不是pod 可分配量

4.5 kubectl top pod 和 docker stats得到的值為什麼不同?

docker stats dockerID 可以看到容器當前的使用量:


如果你的 pod 中只有一個 container,你會發現 docker stats 值不等於kubectl top 的值,既不等於 container_memory_usage_bytes,也不等於container_memory_working_set_bytes。

因為docker stats 和 cadvisor 的計算方式不同,總體值會小於 kubectl top:計算邏輯是:

docker stats = container_memory_usage_bytes - container_memory_cache

五. 後記

一般情況下,我們並不需要時刻關心 node 或 pod 的使用量,因為有集群自動擴縮容(cluster-autoscaler)和 pod 水平擴縮容(HPA)來應對這兩種資源變化,資源指標的意義更適合使用 prometheus 來持久化 cadvisor 的數據,用於回溯歷史或者發送報警。

其他補充:

雖然 kubectl top help 中顯示支持 Storage,但直到 1.16 版本仍然不支持

1.13 之前需要 heapster,1.13 以後需要 metric-server,這部分 kubectl top help 的輸出 有誤,裡面只提到了heapster

k8s dashboard 中的監控圖默認使用的是 heapster,切換為 metric-server後數據會異常,需要多部署一個metric-server-scraper 的 pod 來做接口轉換,具體參考 pr:https://github.com/kubernetes/dashboard/pull/3504

六. 參考資料

https://github.com/kubernetes-sigs/metrics-server/issues/193

https://github.com/kubernetes/kubernetes/pull/83247

https://www.cnblogs.com/liuhongru/p/11215447.html

https://github.com/DirectXMan12/k8s-prometheus-adapter/blob/master/docs/walkthrough.md#quantity-values

https://github.com/fabric8io/kansible/blob/master/vendor/k8s.io/kubernetes/docs/design/resources.md

https://erdong.site/linux/system/computer-unit-conversion.html

https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu

https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/6/html/resource_management_guide/sec-memory

https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt

https://www.cnblogs.com/liuhongru/p/11215447.html

https://github.com/moby/moby/issues/10824

https://github.com/docker/cli/pull/80

K8S 進階訓練營,點擊下方圖片了解詳情

相關焦點

  • Kubectl 常用命令大全
    $ kubectl annotate pods foo description-completion命令:用於設置 kubectl 命令自動補全BASH# 在 bash,cluster-info,top,cordon,uncordon,drain,taintcertificate命令:用於證書資源管理,授權等# 例如,當有node節點要向master請求,那麼是需要master節點授權的$ kubectl certificate
  • 運維必備 9 個 kubectl 命令
    kubectl 是 Kubernetes 的一個命令行管理工具,可用於 Kubernetes 上的應用部署和日常管理。本文列舉了 9 個常見的 kubectl 命令,並總結了一些使用技巧,希望可以幫助系統管理員簡化管理工作。對於剛開始使用命令行工具的開發者,最保險的方法是提出問題(讀取操作),而不是發出命令(寫入操作),所以從使用 get 命令開始是個不錯的選擇。
  • 運維必備的 9 個 kubectl 命令
    kubectl 是 Kubernetes 的一個命令行管理工具,可用於 Kubernetes 上的應用部署和日常管理。本文列舉了 9 個常見的 kubectl 命令,並總結了一些使用技巧,希望可以幫助系統管理員簡化管理工作。對於剛開始使用命令行工具的開發者,最保險的方法是提出問題(讀取操作),而不是發出命令(寫入操作),所以從使用 get 命令開始是個不錯的選擇。
  • Kubernetes 入門命令整理及解析
    方便記憶的規律kubernetes命令有一些相通的規律,可以幫助我們快速掌握。打命令的時候一般分四種:get、delete、describe、logs,然後加上對應的資源類型即可GET 獲取資源信息kubectl get all # 查看所有,包括pod,svc 可以在後面加-A即--all-namespaces
  • K8s kubectl 常用命令總結(建議收藏)
    入手了解 kubectl 是非常快速的一個方式,下面,我們就來看看 kubectl 的命令行操作的常用方式。1.kubectl用法詳解kubectl語法kubectl [command] [Type] [NAME] [flags]command: 子命令,用於操作kubernetes集群資源對象的命令,例如:create,delete
  • Kubernetes的kubectl常用命令速記(文中附高清圖)
    雲君在本文中整理了一些語法和操作注意事項,並收集了一些日常工作中常用的kubectl命令,希望能幫助你更快的記憶常用命令。kubectl默認在「$HOME/.kube」目錄中查找一個名為config的配置文件。你可以通過設置「KUBECONFIG」環境變量或設置「--kubeconfig」參數來指定其它kubeconfig文件。
  • K8s kubectl 複製命令曝目錄遍歷漏洞
    Twistlock 的安全研究人員 Ariel Zelivansky 披露了 Kubernetes kubectl 複製命令的一個目錄遍歷漏洞。
  • 適用於初學者的基本 kubectl 和 Helm 命令 | Linux 中國
    現在我們已經準備好了,讓我們開始 kubectl和 helm 基本命令的購物之旅!用 Helm 列出清單你去商店之前要做的第一件事是什麼?好吧,如果你做事有條理,會創建一個「清單」。同樣,這是我將解釋的第一個基本的 Helm 命令。在一個用 Helm 部署的應用程式中,list 命令提供有關應用程式當前版本的詳細信息。
  • 使用Kubectl管理Kubernetes的全解教程
    對不少IT人員來說,每天與Kubernetes交互的機制一般是通過kubectl——一種命令行工具。kubectl主要用於與Kubernetes API伺服器通信,以在Kubernetes中創建、更新和刪除工作負載。本教程的目的是概述您可以使用的一些常用命令,並提供管理Kubernetes的良好起點。
  • 寫給小白的 kubectl 入門
    動作在 kubectl 中被稱為 command 也就是命令。使用 kubectl --help 能看到可用的命令列表:$ kubectl --helpkubectl controls the Kubernetes cluster manager.
  • Kubectl 插件使用詳解
    Krew 自身也表現為 kubectl 的一個插件,需要以手動方式獨立安裝。Krew 安裝下面的 shell 命令集能自動完成 Krew 插件的安裝,它僅適用於類 UNIX 系統平臺,並以 bash 解釋器運行,其他平臺上的部署方式請參考上面項目地址的官方文檔。
  • k8s 命令詳解(pod,label,job)
    前言上次教程我們講解deployment,replicaset,daemonset 了命令。今天和大家詳解講解下pod,label,job。kubectl 命令詳解 pod查看pod資源(簡略)kubectl get pod參數解析NAME pod名READY 準備好的副本數STATUS 狀態RESTARTS 重啟AGE 已經運行的時間查看pod資源(較詳細)kubectl
  • Kubernetes 之 kubectl 使用指南
    顯示一個或多個資源describe  #顯示資源詳情create    #從文件或標準輸入創建資源update   #從文件或標準輸入更新資源delete   #通過文件名、標準輸入、資源名或者 label 刪除資源log       #輸出 pod 中一個容器的日誌rolling-update  #對指定的 RC 執行滾動升級exec  #在容器內部執行命令
  • kubectl 插件管理工具 krew 使用
    kubectl 插件的全上面周期管理,包括搜索、下載、卸載等。kubectl 其工具已經比較完善,但是對於一些個性化的命令,其宗旨是希望開發者能以獨立而緊張形式發布自定義的kubectl子命令,插件的開發語言不限,需要將最終的腳本或二進位可執行程序以kubectl- 的前綴命名,然後放到PATH中即可,可以使用kubectl plugin list查看目前已經安裝的插件。
  • 5 個冷門但非常實用的 Kubectl 使用技巧,99% 的人都不知道
    kubectl 是 K8s 官方附帶的命令行工具, 可以方便的操作 K8s 集群. 這篇文章主要介紹一些 kubectl 的別樣用法, 希望讀者有一定基礎的 K8s 使用經驗.有一篇文章也介紹了一些技巧, 寫博客的時候正好搜到了, 正好也分享出來吧.
  • Linux top命令12個快捷鍵功能
    Linux top命令12個快捷鍵功能 本文主要講解top命令的一些常用快捷鍵。下面,我們一起來看。這是我們正在進行的Linux命令系列的一部分。我們已經涵蓋了基本的ls命令和cat命令。在本文中,我們嘗試探索top命令,它是我們日常系統管理工作中最常用的命令之一。
  • 聊聊 top 命令中的 CPU 使用率
    命令來查看系統的性能情況,在 top 命令中可以看到很多不同類型的 CPU 使用率,如下圖紅框中標出部分:下面,我們來介紹一下這些 CPU 使用率的意義:us:user time,表示 CPU 執行用戶進程的時間,包括 nice 時間。