一、前言
kubectl top 可以很方便地查看node、pod 的實時資源使用情況:如CPU、內(nèi)存。這篇文章會介紹其數(shù)據(jù)鏈路和實現(xiàn)原理,同時借 kubectl top 闡述 k8s 中的監(jiān)控體系,窺一斑而知全豹。最后會解釋常見的一些問題:
kubectl top 為什么會報錯?
kubectl top node 怎么計算,和節(jié)點上直接 top 有什么區(qū)別?
kubectl top pod 怎么計算,包含 pause 嗎?
kubectl top pod 和exec 進入 pod 后看到的 top 不一樣?
kubectl top pod 和 docker stats得到的值為什么不同?
以下命令的運行環(huán)境為:
k8s 1.8
k8s 1.13
二、使用
kubectl top 是基礎(chǔ)命令,但是需要部署配套的組件才能獲取到監(jiān)控值
1.8以下:部署 heapter
1.8以上:部署 metric-server
kubectl top node: 查看node的使用情況
kubectl top pod: 查看 pod 的使用情況
不指定pod 名稱,則顯示命名空間下所有 pod,–containers可以顯示 pod 內(nèi)所有的container
指標含義:
和 k8s中 的 request、limit 一致,CPU單位100m=0.1 內(nèi)存單位1Mi=1024Ki
pod 的內(nèi)存值是其實際使用量,也是做 limit 限制時判斷 oom 的依據(jù)。pod的使用量等于其所有業(yè)務(wù)容器的總和,不包括 pause 容器,值等于 cadvisr中的 container_memory_working_set_bytes 指標
node 的值并不等于該 node 上所有 pod 值的總和,也不等于直接在機器上運行 top 或 free 看到的值
三、實現(xiàn)原理
3.1 數(shù)據(jù)鏈路
kubectl top、 k8s dashboard 以及 HPA 等調(diào)度組件使用的數(shù)據(jù)是一樣,數(shù)據(jù)鏈路如下:
使用 heapster 時:apiserver 會直接將 metric 請求通過 proxy 的方式轉(zhuǎn)發(fā)給集群內(nèi)的 hepaster 服務(wù)。
而使用 metrics-server 時:apiserver 是通過 /apis/metrics.k8s.io/ 的地址訪問 metric
這里可以對比下 kubect get pod 時的日志:
3.2 metric api
可以發(fā)現(xiàn),heapster 使用的是 proxy 轉(zhuǎn)發(fā),而 metric-server 和普通 pod都是使用 api/xx 的資源接口,heapster采用的這種 proxy 方式是有問題的:
proxy 只是代理請求,一般用于問題排查,不夠穩(wěn)定,且版本不可控
heapster 的接口不能像 apiserver 一樣有完整的鑒權(quán)以及 client 集成,兩邊都維護的話代價高,如 generic apiserver
pod 的監(jiān)控數(shù)據(jù)是核心指標(HPA調(diào)度),應(yīng)該和 pod 本身擁有同等地位,即 metric 應(yīng)該作為一種資源存在,如 metrics.k8s.io 的形式,稱之為 Metric Api
于是官方從 1.8 版本開始逐步廢棄 heapster,并提出了上邊 Metric api 的概念,而 metrics-server 就是這種概念下官方的一種實現(xiàn),用于從 kubelet獲取指標,替換掉之前的 heapster。
3.3 kube-aggregator
有了 metrics-server 組件,采集到了需要的數(shù)據(jù),也暴露了接口,但走到這一步和 heapster 其實沒有區(qū)別,最關(guān)鍵的一步就是如何將打到 apiserver的 /apis/metrics.k8s.io 請求轉(zhuǎn)發(fā)給 metrics-server 組件?解決方案就是:kube-aggregator。kube-aggregator 是對 apiserver 的有力擴展,它允許 k8s 的開發(fā)人員編寫一個自己的服務(wù),并把這個服務(wù)注冊到 k8s 的 api 里面,即擴展 API,metric-server 其實在 1.7版本就已經(jīng)完成了,只是在等 kube-aggregator 的出現(xiàn)。kube-aggregator 是 apiserver 中的實現(xiàn),有些 k8s 版本默認沒開啟,你可以加上這些配置來開啟,他的核心功能是動態(tài)注冊、發(fā)現(xiàn)匯總、安全代理。
如 metric-server 注冊 pod 和 node 時:
3.4 監(jiān)控體系
在提出 metric api 的概念時,官方也提出了新的監(jiān)控體系,監(jiān)控資源被分為了2種:
Core metrics(核心指標):從 Kubelet、cAdvisor 等獲取度量數(shù)據(jù),再由metrics-server 提供給 Dashboard、HPA 控制器等使用。
Custom Metrics(自定義指標):由 Prometheus Adapter 提供 API custom.metrics.k8s.io,由此可支持任意Prometheus采集到的指標。
核心指標只包含 node 和 pod 的 cpu、內(nèi)存等,一般來說,核心指標作 HPA 已經(jīng)足夠,但如果想根據(jù)自定義指標:如請求 qps/5xx 錯誤數(shù)來實現(xiàn) HPA,就需要使用自定義指標了。目前 Kubernetes 中自定義指標一般由 Prometheus 來提供,再利用 k8s-prometheus-adpater 聚合到 apiserver,實現(xiàn)和核心指標同樣的效果。
3.5 kubelet
前面提到,無論是 heapster 還是 metric-server,都只是數(shù)據(jù)的中轉(zhuǎn)和聚合,兩者都是調(diào)用的 kubelet 的 api 接口獲取的數(shù)據(jù),而 kubelet 代碼中實際采集指標的是 cadvisor 模塊,你可以在 node 節(jié)點訪問 10255 端口(1.11版本過后是10250端口)獲取監(jiān)控數(shù)據(jù):
Kubelet Summary metrics: 127.0.0.1:10255/metrics,暴露 node、pod 匯總數(shù)據(jù)
Cadvisor metrics: 127.0.0.1:10255/metrics/cadvisor,暴露 container 維度數(shù)據(jù)
示例,容器的內(nèi)存使用量:
Kubelet 雖然提供了 metric 接口,但實際監(jiān)控邏輯由內(nèi)置的 cAdvisor 模塊負責(zé),演變過程如下:
從k8s 1.6開始,kubernetes 將 cAdvisor 開始集成在kubelet中,不需要單獨配置
從k8s 1.7開始,Kubelet metrics API 不再包含 cadvisor metrics,而是提供了一個獨立的 API 接口來做匯總
從 k8s 1.12 開始,cadvisor 監(jiān)聽的端口在k8s中被刪除,所有監(jiān)控數(shù)據(jù)統(tǒng)一由 Kubelet 的 API 提供
到這里為止,k8s 范圍內(nèi)的監(jiān)控體系就結(jié)束了。
3.6 cadvisor
cadvisor 由谷歌開源,使用 Go 開發(fā),cadvisor 不僅可以搜集一臺機器上所有運行的容器信息,包括 CPU 使用情況、內(nèi)存使用情況、網(wǎng)絡(luò)吞吐量及文件系統(tǒng)使用情況,還提供基礎(chǔ)查詢界面和 http 接口,方便其他組件進行數(shù)據(jù)抓取。在K8S 中集成在 Kubelet 里作為默認啟動項,k8s 官方標配。cadvisor 拿到的數(shù)據(jù)結(jié)構(gòu)示例:
核心邏輯是通過 new 出來的 memoryStorage 以及 sysfs 實例,創(chuàng)建一個manager 實例,manager 的 interface 中定義了許多用于獲取容器和 machine 信息的函數(shù)。
cadvisor的指標解讀:cgroup-v1(https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt) cadvisor 獲取指標時實際調(diào)用的是 runc/libcontainer 庫,而 libcontainer 是對 cgroup 文件 的封裝,即 cadvsior 也只是個轉(zhuǎn)發(fā)者,它的數(shù)據(jù)來自于cgroup 文件。
3.7 cgroup
cgroup 文件中的值是監(jiān)控數(shù)據(jù)的最終來源,如
mem usage 的值,來自于
/sys/fs/cgroup/memory/docker/[containerId]/memory.usage_in_bytes
如果沒限制內(nèi)存,Limit=machine_mem,否則來自于
/sys/fs/cgroup/memory/docker/[id]/memory.limit_in_bytes
內(nèi)存使用率=memory.usage_in_bytes/memory.limit_in_bytes
一般情況下,cgroup文件夾下的內(nèi)容包括CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)等信息:
如 memory 下的幾個常用的指標含義:
memory.stat 中的信息是最全的:
原理到這里結(jié)束,這里解釋下最開始的 kubectl top 的幾個問題:
四、問題
一般情況下 top 報錯有以下幾種,可以 kubectl top pod -v=10看到具體的調(diào)用日志:
沒有部署 heapster 或者 metric-server,或者 pod 運行異常,可以排查對應(yīng) pod 日志
要看的 pod 剛剛建出來,還沒來得及采集指標,報 not found 錯誤,默認 1 分鐘
以上兩種都不是,可以檢查下 kubelet 的 10255 端口是否開放,默認情況下會使用這個只讀端口獲取指標,也可以在 heapster 或 metric-server 的配置中增加證書,換成 10250 認證端口
4.2 kubectl top pod 內(nèi)存怎么計算,包含 pause容器嗎
每次啟動 pod,都會有一個 pause 容器,既然是容器就一定有資源消耗(一般在 2-3M 的內(nèi)存),cgroup 文件中,業(yè)務(wù)容器和 pause 容器都在同一個 pod的文件夾下。
但 cadvisor 在查詢 pod 的內(nèi)存使用量時,是先獲取了 pod 下的container列表,再逐個獲取container的內(nèi)存占用,不過這里的 container 列表并沒有包含 pause,因此最終 top pod 的結(jié)果也不包含 pause 容器pod 的內(nèi)存使用量計算kubectl top pod 得到的內(nèi)存使用量,并不是 cadvisor 中的 container_memory_usage_bytes,而是 container_memory_working_set_bytes,計算方式為:
container_memory_usage_bytes = container_memory_rss + container_memory_cache + kernel memory
container_memory_working_set_bytes = container_memory_usage_bytes – total_inactive_file(未激活的匿名緩存頁)
container_memory_working_set_bytes 是容器真實使用的內(nèi)存量,也是 limit限制時的 oom 判斷依據(jù)。cadvisor 中的 container_memory_usage_bytes 對應(yīng) cgroup 中的 memory.usage_in_bytes 文件,但 container_memory_working_set_bytes 并沒有具體的文件,他的計算邏輯在 cadvisor 的代碼中,如下:
同理,node 的內(nèi)存使用量也是 container_memory_working_set_bytes。
4.3 kubectl top node 怎么計算,和節(jié)點上直接 top 有什么區(qū)別
kubectl top node 得到的 cpu 和內(nèi)存值,并不是節(jié)點上所有 pod 的總和,不要直接相加。top node 是機器上 cgroup 根目錄下的匯總統(tǒng)計。
在機器上直接 top 命令看到的值和 kubectl top node 不能直接對比,因為計算邏輯不同,如內(nèi)存,大致的對應(yīng)關(guān)系是(前者是機器上 top,后者是 kubectl top):
rss + cache = (in)active_anon + (in)active_file
4.4 kubectl top pod 和 exec 進入 pod 后看到的 top 不一樣
top 命令的差異和上邊一致,無法直接對比,同時,就算你對 pod 做了 limit 限制,pod 內(nèi)的 top 看到的內(nèi)存和 cpu 總量仍然是機器總量,并不是pod 可分配量
進程的RSS為進程使用的所有物理內(nèi)存(file_rss+anon_rss),即Anonymous pages+Mapped apges(包含共享內(nèi)存)
cgroup RSS為(anonymous and swap cache memory),不包含共享內(nèi)存。兩者都不包含file cache
4.5 kubectl top pod 和 docker stats得到的值為什么不同?
docker stats dockerID 可以看到容器當(dāng)前的使用量:
如果你的 pod 中只有一個 container,你會發(fā)現(xiàn) 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
五、后記
一般情況下,我們并不需要時刻關(guān)心 node 或 pod 的使用量,因為有集群自動擴縮容(cluster-autoscaler)和 pod 水平擴縮容(HPA)來應(yīng)對這兩種資源變化,資源指標的意義更適合使用 prometheus 來持久化 cadvisor 的數(shù)據(jù),用于回溯歷史或者發(fā)送報警。其他補充:
雖然 kubectl top help 中顯示支持 Storage,但直到 1.16 版本仍然不支持
1.13 之前需要 heapster,1.13 以后需要 metric-server,這部分 kubectl top help 的輸出 有誤,里面只提到了heapster
k8s dashboard 中的監(jiān)控圖默認使用的是 heapster,切換為 metric-server后數(shù)據(jù)會異常,需要多部署一個metric-server-scraper 的 pod 來做接口轉(zhuǎn)換
-
cpu
+關(guān)注
關(guān)注
68文章
10863瀏覽量
211797 -
監(jiān)控
+關(guān)注
關(guān)注
6文章
2208瀏覽量
55209 -
數(shù)據(jù)鏈路
+關(guān)注
關(guān)注
0文章
25瀏覽量
8944
原文標題:從 Kubectl Top 說起, 談?wù)?Kubernetes 是如何進行資源監(jiān)控的?
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論