控實(shí)戰(zhàn):Metrics Server與Dashboard部署全解析)
搞Kubernetes運(yùn)維的朋友應(yīng)該都有這種經(jīng)歷集群跑起來(lái)了Pod也在轉(zhuǎn)但是你想看看每個(gè)節(jié)點(diǎn)還剩多少內(nèi)存、某個(gè)應(yīng)用最近半小時(shí)CPU是不是飆了卻發(fā)現(xiàn)無(wú)從下手。直接kubectl top node敲下去報(bào)錯(cuò)說(shuō)metrics API不可用因?yàn)闆](méi)有部署采集組件。這時(shí)候最經(jīng)典也最實(shí)用的一套組合拳就是Kubernetes監(jiān)控里最常見(jiàn)的搭配Metrics Server負(fù)責(zé)采集節(jié)點(diǎn)和Pod的CPU、內(nèi)存數(shù)據(jù)Dashboard負(fù)責(zé)把數(shù)據(jù)變成可視化的界面。今天這篇就把這套監(jiān)控組合從部署到排查完整走一遍講清楚每一步的原理、選擇和避坑點(diǎn)。這套方案適合誰(shuí)適合剛把集群跑起來(lái)、需要基礎(chǔ)資源監(jiān)控看板的運(yùn)維和開(kāi)發(fā)也適合準(zhǔn)備自己搭一套輕量監(jiān)控體系、但暫時(shí)不想上Prometheus那套重型方案的人。它能解決的核心問(wèn)題很直接在Dashboard里直接看節(jié)點(diǎn)和Pod的歷史與實(shí)時(shí)資源占用曲線執(zhí)行kubectl top不再報(bào)錯(cuò)HPA也能正常拿到指標(biāo)。1. 基礎(chǔ)認(rèn)知為什么是Metrics Server加Dashboard1.1 先搞清楚Kubernetes監(jiān)控體系的分層Kubernetes監(jiān)控不是一個(gè)單一的東西而是分了好幾層。從下往上大致是物理資源層節(jié)點(diǎn)CPU、內(nèi)存、磁盤(pán)、系統(tǒng)組件層kubelet、API Server、調(diào)度器自己的狀態(tài)、應(yīng)用層容器內(nèi)的業(yè)務(wù)指標(biāo)比如請(qǐng)求量、延遲和事件層Pod調(diào)度失敗、驅(qū)逐等。我們平時(shí)聊的先搭個(gè)監(jiān)控看看絕大多數(shù)場(chǎng)景指的都是第一層也就是資源指標(biāo)。這批數(shù)據(jù)的來(lái)源是每臺(tái)節(jié)點(diǎn)上的kubelet它內(nèi)置了一個(gè)叫cAdvisor的組件負(fù)責(zé)采集容器和節(jié)點(diǎn)的CPU、內(nèi)存、網(wǎng)絡(luò)、磁盤(pán)等原始數(shù)據(jù)。難點(diǎn)在于kubelet把數(shù)據(jù)采上來(lái)之后是通過(guò)一個(gè)本地接口暴露的你不可能每次都跑到每臺(tái)機(jī)器上去看。所以需要一個(gè)集群層面的組件把這些數(shù)據(jù)匯總并且按照標(biāo)準(zhǔn)的Kubernetes API方式暴露出來(lái)。這就是Metrics Server的核心價(jià)值。它把kubelet采集到的數(shù)據(jù)聚合然后注冊(cè)成metrics.k8s.io這個(gè)API之后你用kubectl top也好Dashboard也好HPA也好都從這個(gè)API拿數(shù)據(jù)。1.2 為什么第一套監(jiān)控推薦這兩個(gè)而不是直接上Prometheus很多人會(huì)覺(jué)得既然要做監(jiān)控為什么不一步到位直接上Prometheus加Grafana我的看法是分階段。Prometheus體系功能強(qiáng)大但學(xué)習(xí)曲線和組件數(shù)量都不是零成本的你需要部署Prometheus自身、node-exporter、kube-state-metrics還要學(xué)PromQL寫(xiě)查詢這對(duì)剛接觸Kubernetes監(jiān)控的人來(lái)說(shuō)是個(gè)不小的臺(tái)階。Metrics Server配合Dashboard這套組合的優(yōu)勢(shì)在于輕量、官方維護(hù)、零查詢語(yǔ)言負(fù)擔(dān)。Metrics Server本身就是Kubernetes官方的插件部署起來(lái)就是一組鏡像加幾個(gè)YAML。Dashboard同樣是官方項(xiàng)目提供了Web界面點(diǎn)幾下就能看到集群資源水位。它不追求深度分析但能把節(jié)點(diǎn)是不是快滿了哪個(gè)Pod在持續(xù)占內(nèi)存這類(lèi)最要命的問(wèn)題用曲線直觀呈現(xiàn)出來(lái)。等這套基礎(chǔ)監(jiān)控跑明白了再上Prometheus做更細(xì)粒度的告警和歷史數(shù)據(jù)持久化是更平滑的路徑。1.3 這套組合的數(shù)據(jù)通路到底是怎么走的先說(shuō)清一條完整的數(shù)據(jù)鏈路后面排查問(wèn)題全靠它。Pod在節(jié)點(diǎn)上跑節(jié)點(diǎn)上的kubelet通過(guò)cAdvisor采集容器CPU和內(nèi)存的使用數(shù)據(jù)。Metrics Server通過(guò)kubelet的10250端口的只讀接口把每個(gè)Pod的指標(biāo)樣本抓取下來(lái)聚合后緩存在自己的內(nèi)存里并且通過(guò)Kubernetes的聚合API層注冊(cè)成metrics.k8s.io。Dashboard在展示資源圖表時(shí)向后端API Server發(fā)起查詢API Server把請(qǐng)求代理給Metrics ServerMetrics Server返回內(nèi)存里的緩存數(shù)據(jù)Dashboard再繪制成曲線圖。這條鏈路里有三個(gè)關(guān)鍵點(diǎn)值得圈出來(lái)Metrics Server本身不落庫(kù)數(shù)據(jù)是內(nèi)存中的臨時(shí)快照所以你看不到很久以前的歷史數(shù)據(jù)默認(rèn)只保留最近幾分鐘的窗口。metrics.k8s.io這個(gè)API是聚合API由APIService對(duì)象注冊(cè)檢查這個(gè)對(duì)象的健康狀態(tài)是排查kubectl top沒(méi)數(shù)據(jù)的第一步。Dashboard查詢的是實(shí)時(shí)指標(biāo)它本身不直接和kubelet通信所有數(shù)據(jù)都經(jīng)過(guò)API Server代理所以權(quán)限模型走的是RBAC那一套Dashboard需要配置ServiceAccount和對(duì)應(yīng)的ClusterRole。理解這條鏈路之后你就會(huì)發(fā)現(xiàn)很多所謂奇怪的問(wèn)題其實(shí)一點(diǎn)都不奇怪只是鏈路里某個(gè)環(huán)節(jié)沒(méi)就位。2. 部署前準(zhǔn)備版本適配與工具選型2.1 版本適配是第一個(gè)隱形坑我見(jiàn)過(guò)太多人部署失敗第一反應(yīng)是網(wǎng)絡(luò)問(wèn)題或者YAML寫(xiě)錯(cuò)了其實(shí)往往是被版本適配坑的。Metrics Server和Kubernetes主版本之間是有對(duì)應(yīng)關(guān)系的不匹配的時(shí)候會(huì)出現(xiàn)證書(shū)校驗(yàn)失敗、API無(wú)法注冊(cè)這類(lèi)莫名其妙的問(wèn)題。以當(dāng)前主流版本為例Kubernetes 1.19到1.25對(duì)應(yīng)Metrics Server v0.6.x鏡像是registry.k8s.io/metrics-server/metrics-server:v0.6.4。Kubernetes 1.26及以上推薦Metrics Server v0.7.x或者更新的v1.x版本因?yàn)閗ubelet的TLS證書(shū)行為有變化舊版本會(huì)握手失敗。還需要留意容器運(yùn)行時(shí)。如果節(jié)點(diǎn)用的containerd而不用DockerMetrics Server本身沒(méi)影響但Dashboard的鏡像拉取策略和網(wǎng)絡(luò)設(shè)置有時(shí)會(huì)有小坑這個(gè)后面會(huì)單獨(dú)說(shuō)。判斷版本匹配的一個(gè)笨但有效的辦法去Metrics Server官方GitHub的README里找到Compatibility表格對(duì)著看。不要憑感覺(jué)選最新版本最新版本不一定兼容你的集群。2.2 我用的環(huán)境與工具清單我這次演示的標(biāo)準(zhǔn)環(huán)境是某公司內(nèi)部測(cè)試集群用kubeadm方式安裝的Kubernetes v1.28版節(jié)點(diǎn)上容器運(yùn)行時(shí)為containerd網(wǎng)絡(luò)插件用的是Calico。這樣的環(huán)境應(yīng)該能覆蓋大部分生產(chǎn)或測(cè)試場(chǎng)景的共性。需要用到的工具有kubectl本地操作集群的客戶端版本最好和集群小版本差異不超過(guò)一個(gè)版本。helm雖然這篇主要以純YAML部署為主但我會(huì)提到用helm做Dashboard部署的替代方式官方chart維護(hù)起來(lái)會(huì)方便一些。瀏覽器加一個(gè)SSH端口轉(zhuǎn)發(fā)工具因?yàn)镈ashboard大多數(shù)時(shí)候不會(huì)暴露成LoadBalancer服務(wù)而是通過(guò)kubectl port-forward訪問(wèn)。強(qiáng)調(diào)一下雖然我用的是RHEL類(lèi)的Linux發(fā)行版做跳板機(jī)但kubectl port-forward的用法在所有平臺(tái)上都一樣。2.3 為什么建議用官方Y(jié)AML而不是自己寫(xiě)Metrics Server和Dashboard官方都提供了標(biāo)準(zhǔn)的部署YAML分別是components.yaml和recommended.yaml。直接用的理由有三個(gè)第一這兩份文件里的鏡像地址、權(quán)限綁定、啟動(dòng)參數(shù)都是經(jīng)過(guò)大量生產(chǎn)環(huán)境驗(yàn)證的自己拍腦袋寫(xiě)的配置很容易漏掉必需的參數(shù)比如--kubelet-preferred-address-typesInternalIP這類(lèi)細(xì)節(jié)。第二官方文件里有配套的RBAC對(duì)象ServiceAccount、ClusterRole、ClusterRoleBinding都是齊的少一個(gè)Dashboard就登錄不進(jìn)去。第三升級(jí)的時(shí)候直接替換文件就能平滑跟進(jìn)不用手工比對(duì)差異。當(dāng)然直接用不意味著閉眼用。內(nèi)網(wǎng)環(huán)境拉不了外部鏡像的情況很常見(jiàn)你需要提前把鏡像docker pull或者ctr pull下來(lái)打上tag推到自己的私有倉(cāng)庫(kù)然后修改YAML里的image字段。這是標(biāo)準(zhǔn)的離線部署操作后面排查章節(jié)會(huì)再提到和鏡像拉取相關(guān)的坑。2.4 端口和網(wǎng)絡(luò)層面的預(yù)期Metrics Server跑起來(lái)后默認(rèn)監(jiān)聽(tīng)443端口它需要訪問(wèn)每個(gè)節(jié)點(diǎn)的kubelet 10250端口。這一步在使用網(wǎng)絡(luò)安全策略NetworkPolicy的集群里尤其要留意如果那個(gè)命名空間默認(rèn)禁止進(jìn)站流量Metrics Server到節(jié)點(diǎn)的抓取會(huì)失敗表現(xiàn)就是Pod起來(lái)了但所有指標(biāo)都拉不到甚至API注冊(cè)不成功。Dashboard主容器默認(rèn)監(jiān)聽(tīng)8443端口通過(guò)kubectl port-forward直接轉(zhuǎn)發(fā)到本地的某個(gè)端口訪問(wèn)。如果集群里的Ingress已經(jīng)配置好也可以選擇用Ingress暴露但需要額外處理TLS證書(shū)和Dashboard自身的認(rèn)證方式我建議你在第一次部署時(shí)就用端口轉(zhuǎn)發(fā)簡(jiǎn)單直接。3. Metrics Server部署與深度解析3.1 部署Metrics Server的標(biāo)準(zhǔn)步驟部署的第一步是拉取官方清單文件。wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml然后直接應(yīng)用kubectl apply -f components.yaml等一兩分鐘檢查Pod狀態(tài)kubectl get pods -n kube-system -l app.kubernetes.io/namemetrics-server正常情況下應(yīng)該看到類(lèi)似這樣的輸出NAME READY STATUS RESTARTS AGE metrics-server-7d5b6d9c9b-x4k2m 1/1 Running 0 96s接著驗(yàn)證API是否注冊(cè)成功kubectl get apiservice v1beta1.metrics.k8s.io輸出中的AVAILABLE列應(yīng)該是True。這一步是我在所有集群上的必查項(xiàng)因?yàn)镻od處于Running狀態(tài)并不能說(shuō)明API一定可用。再驗(yàn)證數(shù)據(jù)采集是否正常kubectl top node kubectl top pod -A如果你看到類(lèi)似error: metrics not available yet的提示先別慌多數(shù)情況下只是因?yàn)镸etrics Server才啟動(dòng)第一輪采集還沒(méi)完成。等一分鐘再敲一次。如果反復(fù)都是這個(gè)錯(cuò)誤就需要按第五章的排查思路去查了。3.2 核心原理聚合API與參數(shù)選擇Metrics Server能讓你用kubectl top這種原生命令查指標(biāo)是因?yàn)镵ubernetes提供了一套聚合API機(jī)制。簡(jiǎn)單說(shuō)你可以自己寫(xiě)一個(gè)后端服務(wù)提供一組特定格式的API然后通過(guò)創(chuàng)建APIService對(duì)象告訴API Server這個(gè)路徑的請(qǐng)求代理給那個(gè)服務(wù)處理。Metrics Server正是這么做的它把自己注冊(cè)成了metrics.k8s.io這個(gè)API組。在components.yaml里你可能會(huì)注意到Metrics Server Deployment里有一堆啟動(dòng)參數(shù)這些參數(shù)是部署后能不能成功采數(shù)據(jù)的關(guān)鍵。拿最常見(jiàn)的幾個(gè)來(lái)說(shuō)--kubelet-preferred-address-typesInternalIP告訴Metrics Server優(yōu)先使用節(jié)點(diǎn)的內(nèi)網(wǎng)IP去訪問(wèn)kubelet而不是主機(jī)名。如果你的集群DNS解析有問(wèn)題不加這個(gè)參數(shù)會(huì)解析到錯(cuò)誤地址導(dǎo)致抓取失敗。--cert-dir/tmpMetrics Server自己也需要TLS證書(shū)默認(rèn)會(huì)掛載一個(gè)臨時(shí)目錄存放自簽證書(shū)。如果你看到日志里報(bào)找不到證書(shū)多半是CERT_DIR沒(méi)有指向Deployment里指定的volume路徑。--kubelet-use-node-status-port新版本默認(rèn)行為是使用節(jié)點(diǎn)狀態(tài)里上報(bào)的端口適用面更廣。另一個(gè)需要理解的點(diǎn)是cAdvisor數(shù)據(jù)源。Metrics Server本身不采集數(shù)據(jù)它是向每個(gè)節(jié)點(diǎn)上的kubelet發(fā)請(qǐng)求kubelet再?gòu)腸Advisor拿數(shù)據(jù)返回。所以如果你單獨(dú)啟用了某種運(yùn)行時(shí)隔離策略或者kubelet配置了自定義的cgroup驅(qū)動(dòng)Metrics Server得到的數(shù)值可能會(huì)和你在宿主機(jī)上用free看到的有偏差這在容器化資源統(tǒng)計(jì)里是正常的不用糾結(jié)。3.3 鏡像拉取問(wèn)題的常見(jiàn)解法國(guó)內(nèi)網(wǎng)絡(luò)環(huán)境拉registry.k8s.io的鏡像經(jīng)常失敗這是部署Metrics Server時(shí)最普遍的障礙。解決方案很直接用鏡像代理或者先拉到本地再推私有倉(cāng)庫(kù)。以containerd運(yùn)行時(shí)為例可以這樣操作ctr -n k8s.io images pull registry.k8s.io/metrics-server/metrics-server:v0.6.4如果這個(gè)地址也超時(shí)可以用一些公共鏡像倉(cāng)庫(kù)的代理地址先拉取然后重新打tagctr -n k8s.io images pull docker.io/mirrorgooglecontainers/metrics-server:v0.6.4 ctr -n k8s.io images tag docker.io/mirrorgooglecontainers/metrics-server:v0.6.4 registry.k8s.io/metrics-server/metrics-server:v0.6.4然后修改components.yaml里的image字段指向你自己的私有倉(cāng)庫(kù)地址再apply即可。需要注意改鏡像地址的同時(shí)imagePullPolicy最好設(shè)置成IfNotPresent避免節(jié)點(diǎn)在鏡像已經(jīng)存在的情況下還要去遠(yuǎn)程倉(cāng)庫(kù)校驗(yàn)。3.4 高可用與多副本部署生產(chǎn)環(huán)境如果只有單副本Metrics Server一旦Pod被重新調(diào)度監(jiān)控會(huì)短暫中斷。用Deployment默認(rèn)的replicas: 1在測(cè)試環(huán)境沒(méi)問(wèn)題但如果有條件建議調(diào)整為兩個(gè)副本spec: replicas: 2 strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1配兩個(gè)副本之后還需要在spec.template.spec里加上調(diào)度分散的配置比如podAntiAffinity讓兩個(gè)Pod盡量不落在同一節(jié)點(diǎn)上。另外多副本模式有個(gè)細(xì)節(jié)Metrics Server的啟動(dòng)參數(shù)里不要加--metric-resolution這種會(huì)導(dǎo)致數(shù)據(jù)不一致的參數(shù)保持默認(rèn)即可因?yàn)槊總€(gè)副本都是獨(dú)立從kubelet抓取數(shù)據(jù)是同一份快照副本之間不需要同步。3.5 安全加固限制Metrics Server的訪問(wèn)范圍Metrics Server作為集群內(nèi)的一個(gè)高權(quán)限組件它默認(rèn)可以獲取所有命名空間的資源指標(biāo)。如果集群安全要求嚴(yán)可以通過(guò)RBAC對(duì)它做約束。components.yaml里有個(gè)ClusterRole叫system:metrics-server它的規(guī)則列表指定了可以讀取nodes/metrics、pods等資源。盡量不要去擴(kuò)大它的權(quán)限范圍如果業(yè)務(wù)上有隔離需求可以考慮用--metric-resolution和--kubelet-only組合限制它只從kubelet拿數(shù)據(jù)不讓它直接訪問(wèn)Pod的Exec接口之類(lèi)的。另外Metrics Server的ServiceAccount在kube-system命名空間平時(shí)很少被單獨(dú)審計(jì)建議在部署后第一時(shí)間給這個(gè)ServiceAccount打上標(biāo)簽方便后續(xù)結(jié)合策略引擎做異常檢測(cè)。4. Dashboard部署與登錄配置4.1 部署Dashboard主體Metrics Server是數(shù)據(jù)采集層Dashboard是展示層兩者配合起來(lái)才能看到曲線。Dashboard官方提供的部署文件叫recommended.yaml里面包含了所有必要資源對(duì)象。kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml這個(gè)清單會(huì)創(chuàng)建kubernetes-dashboard命名空間部署Deployment、Service、ServiceAccount還有一系列RBAC規(guī)則。默認(rèn)情況下Dashboard的Service類(lèi)型是ClusterIP端口443這意味著只有集群內(nèi)部可以訪問(wèn)。這也是我們接下來(lái)需要用端口轉(zhuǎn)發(fā)訪問(wèn)的原因。查看Dashboard Pod狀態(tài)kubectl get pods -n kubernetes-dashboard因?yàn)镈ashboard鏡像比較大加上有時(shí)候解析慢Pod在ContainerCreating階段多停一會(huì)兒是正常的。遇到ImagePullBackOff就按鏡像拉取問(wèn)題處理思路和前面Metrics Server一樣。4.2 Dashboard的認(rèn)證方式Token登錄Dashboard默認(rèn)不支持賬號(hào)密碼登錄可以用兩種方式認(rèn)證一種是Kubeconfig一種是Token。實(shí)際運(yùn)維里Token方式最常用因?yàn)樗灰蕾嘖ubernetes自身的ServiceAccount機(jī)制不需要額外配置。創(chuàng)建一個(gè)專(zhuān)門(mén)給Dashboard用的管理員ServiceAccountapiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard再創(chuàng)建一個(gè)ClusterRoleBinding把它綁到集群管理員角色上apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard然后取得這個(gè)ServiceAccount的Token。新版本Kubernetes里ServiceAccount會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的Secret名稱一般是admin-user-token-xxxxx。獲取令牌的命令是kubectl -n kubernetes-dashboard create token admin-user這條命令會(huì)生成一個(gè)有時(shí)效的Token默認(rèn)有效期為1小時(shí)適合臨時(shí)登錄。如果你希望Token長(zhǎng)期有效傳統(tǒng)做法是直接讀取Secret里的token字段kubectl get secret -n kubernetes-dashboard $(kubectl get secret -n kubernetes-dashboard -lapp.kubernetes.io/componentkubernetes-dashboard -o jsonpath{.items[0].metadata.name}) -o jsonpath{.data.token} | base64 -d不過(guò)提醒一句長(zhǎng)期Token增加了泄露風(fēng)險(xiǎn)。如果是臨時(shí)演示或排查用create token就好如果需要長(zhǎng)期用建議通過(guò)外部密鑰管理系統(tǒng)來(lái)簽發(fā)和輪換而不是把Token硬編碼到腳本里。4.3 訪問(wèn)Dashboard端口轉(zhuǎn)發(fā)與Ingress選型登錄和訪問(wèn)是很多人第一次卡住的地方。端口轉(zhuǎn)發(fā)的方式很簡(jiǎn)單在一臺(tái)能連通Kubernetes API Server的機(jī)器上執(zhí)行kubectl port-forward -n kubernetes-dashboard service/kubernetes-dashboard 8080:443然后本地瀏覽器訪問(wèn)https://localhost:8080瀏覽器會(huì)提示證書(shū)不受信任這是正常的因?yàn)镈ashboard用的是自簽證書(shū)選擇繼續(xù)訪問(wèn)即可。需要注意端口轉(zhuǎn)發(fā)只適合臨時(shí)使用或者你本機(jī)直連的情況。如果集群有多個(gè)節(jié)點(diǎn)其他同事也要訪問(wèn)Dashboard每次都讓人家自己轉(zhuǎn)發(fā)就很麻煩。這時(shí)候可以配置Ingress。Dashboard的Service是HTTPS的所以Ingress需要配置TLS后端協(xié)議也要設(shè)為HTTPS。具體的注解取決于你用的Ingress Controller以常見(jiàn)的Nginx Ingress為例apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: dashboard namespace: kubernetes-dashboard annotations: nginx.ingress.kubernetes.io/backend-protocol: HTTPS nginx.ingress.kubernetes.io/ssl-passthrough: true spec: ingressClassName: nginx tls: - hosts: - dashboard.example.com secretName: kubernetes-dashboard-tls rules: - host: dashboard.example.com http: paths: - path: / pathType: Prefix backend: service: name: kubernetes-dashboard port: number: 443這里用了ssl-passthrough因?yàn)镈ashboard是自簽HTTPS證書(shū)如果Ingress再終止TLS會(huì)多一層證書(shū)問(wèn)題。生產(chǎn)環(huán)境建議把Dashboard置于內(nèi)部域名下不要暴露到公網(wǎng)畢竟Dashboard有集群管理權(quán)限暴露公網(wǎng)等于把鑰匙掛在門(mén)上。4.4 登錄后的界面布局與核心功能用Token登錄后你會(huì)進(jìn)入Dashboard主界面。左側(cè)導(dǎo)航有幾個(gè)核心區(qū)域先說(shuō)最常用的。集群概覽頂部直接展示節(jié)點(diǎn)數(shù)、命名空間數(shù)、內(nèi)存請(qǐng)求總量等摘要數(shù)字下方是按節(jié)點(diǎn)排列的資源使用量條形圖。節(jié)點(diǎn)列表點(diǎn)開(kāi)某個(gè)節(jié)點(diǎn)可以看到該節(jié)點(diǎn)上所有Pod的列表以及每個(gè)Pod的實(shí)時(shí)CPU、內(nèi)存占用還有節(jié)點(diǎn)的壓力狀態(tài)。工作負(fù)載按Deployment、StatefulSet、DaemonSet等分類(lèi)查看點(diǎn)進(jìn)去能看到每個(gè)工作負(fù)載的Pod列表、重啟次數(shù)、調(diào)度事件以及日志入口。服務(wù)和Ingress查看服務(wù)暴露方式調(diào)試端口映射很方便。垂直P(pán)od自動(dòng)擴(kuò)縮容和水平Pod自動(dòng)擴(kuò)縮容如果你配置了HPADashboard里可以直接看到當(dāng)前目標(biāo)指標(biāo)和實(shí)際指標(biāo)值。Dashboard里最讓我受用的一個(gè)功能是查看某個(gè)Pod的日志不再需要kubectl logs -f一條條敲。有一個(gè)點(diǎn)必須提醒Dashboard默認(rèn)顯示的CPU指標(biāo)是Core數(shù)量?jī)?nèi)存是字節(jié)數(shù)如果你在圖表里看到數(shù)值變化規(guī)律詭異先確認(rèn)單位再下結(jié)論。4.5 自定義Dashboard資源配額與隔離如果團(tuán)隊(duì)里有多個(gè)人共同使用Dashboard通常不希望所有人都拿到cluster-admin權(quán)限。更合理的做法是按角色拆分查看類(lèi)權(quán)限綁定到view這個(gè)ClusterRole需要重啟Pod的再給一個(gè)包含delete權(quán)限的自定義Role。Dashboard自帶的RBAC模型和Kubernetes原生的RBAC是一致的所以控制好ServiceAccount的權(quán)限就控制了Dashboard的權(quán)限。如果你在Dashboard里創(chuàng)建了自定義資源比如某個(gè)命名空間下的DeploymentDashboard會(huì)直接用你的ServiceAccount身份去調(diào)用API Server權(quán)限校驗(yàn)是實(shí)時(shí)的。這個(gè)設(shè)計(jì)既方便又危險(xiǎn)有時(shí)候你在Dashboard里刪東西刪不掉是因?yàn)楫?dāng)前Token對(duì)應(yīng)的角色沒(méi)有對(duì)應(yīng)命名空間的刪除權(quán)限這恰恰說(shuō)明權(quán)限隔離生效了是好事。5. 實(shí)操過(guò)程從零到有一次完整走通5.1 完整命令時(shí)間線為了讓你對(duì)這個(gè)過(guò)程有整體把握我把從零部署到成功看到Pod曲線的完整命令時(shí)間線放在這里。這部分每一行我都實(shí)際跑過(guò)你可以照抄。第一段部署Metrics Serverkubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml等Pod起來(lái)之后驗(yàn)證kubectl get pods -n kube-system -l app.kubernetes.io/namemetrics-server kubectl get apiservice v1beta1.metrics.k8s.io kubectl top node第二段部署Dashboardkubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml kubectl get pods -n kubernetes-dashboard -w第三段創(chuàng)建登錄賬號(hào)和獲取Tokenkubectl create -f dashboard-adminuser.yaml kubectl -n kubernetes-dashboard create token admin-user第四段訪問(wèn)Dashboardkubectl port-forward -n kubernetes-dashboard service/kubernetes-dashboard 8080:443瀏覽器打開(kāi)https://localhost:8080粘貼Token登錄。進(jìn)到界面以后點(diǎn)節(jié)點(diǎn)列表找到某個(gè)節(jié)點(diǎn)點(diǎn)擊進(jìn)去在Dashboards那個(gè)區(qū)域就能看到CPU和內(nèi)存的曲線圖。5.2 理解你看到的指標(biāo)CPU與內(nèi)存曲線怎么讀登錄Dashboard之后很多人第一反應(yīng)是這曲線怎么看著不對(duì)。這里把讀圖的邏輯講清楚。Dashboard里節(jié)點(diǎn)的CPU使用率是Metrics Server返回的實(shí)時(shí)樣本它代表的是節(jié)點(diǎn)上所有容器進(jìn)程CPU使用量的總和除以節(jié)點(diǎn)可分配的CPU核數(shù)。注意它不包含系統(tǒng)進(jìn)程和內(nèi)核本身的開(kāi)銷(xiāo)所以你會(huì)看到節(jié)點(diǎn)CPU使用率即使業(yè)務(wù)很忙也很難沖到100%因?yàn)橛幸徊糠諧PU被kubelet、系統(tǒng)守護(hù)進(jìn)程等占用但Metrics Server沒(méi)有統(tǒng)計(jì)進(jìn)去。內(nèi)存同理節(jié)點(diǎn)內(nèi)存使用率是Pod實(shí)際占用的量不包含Page Cache因此和free命令看到的used差別很大是正常的。某個(gè)Pod的CPU曲線出現(xiàn)尖峰不代表就是應(yīng)用故障有可能是初始化容器在跑數(shù)據(jù)遷移或者Java應(yīng)用的JIT編譯瞬間占滿核。要結(jié)合重啟次數(shù)和調(diào)度事件一起判斷才不容易誤判故障。我自己踩過(guò)這樣的坑一個(gè)Pod因?yàn)镺OMKilled反復(fù)重啟但CPU曲線看起來(lái)一點(diǎn)都不忙后來(lái)發(fā)現(xiàn)是內(nèi)存配額設(shè)置得太低OOM發(fā)生在內(nèi)存維度跟CPU沒(méi)關(guān)系。5.3 讓Dashboard顯示HPA目標(biāo)指標(biāo)Dashboard支持查看HPA狀態(tài)前提是你的集群里已經(jīng)安裝了Metrics Server。在Dashboard左側(cè)導(dǎo)航找Horizontal Pod Autoscalers打開(kāi)某個(gè)HPA的詳情頁(yè)能看到目標(biāo)指標(biāo)比如CPU利用率的當(dāng)前值和目標(biāo)值。如果當(dāng)前值一直顯示unknown基本可以斷定Metrics Server沒(méi)有就緒回到第3章去查。這里有一個(gè)配置細(xì)節(jié)值得單獨(dú)說(shuō)HPA如果想按Pod的平均CPU利用率擴(kuò)縮容需要在Deployment上設(shè)置正確的resources.requests.cpu因?yàn)镠PA的利用率是當(dāng)前使用量除以請(qǐng)求量沒(méi)有requestsHPA就沒(méi)有計(jì)算基礎(chǔ)Dashboard上也沒(méi)法顯示百分比。很多人部署了HPA但一直不生效問(wèn)題往往出在資源請(qǐng)求沒(méi)有設(shè)置。5.4 實(shí)操中我建議你補(bǔ)充的三個(gè)小工具M(jìn)etrics Server和Dashboard不是萬(wàn)能的它們?cè)跉v史趨勢(shì)、告警方面很弱所以我在實(shí)踐里會(huì)給這套組合補(bǔ)充三個(gè)輕量工具kube-state-metrics它把集群里各種對(duì)象的狀態(tài)變成Prometheus格式的指標(biāo)比如Deployment的期望副本數(shù)和實(shí)際副本數(shù)。Metrics Server只關(guān)心運(yùn)行中的Pod資源使用而kube-state-metrics能反映配置層面的漂移。node-problem-detector檢測(cè)節(jié)點(diǎn)層面的異常比如內(nèi)核死鎖、容器運(yùn)行時(shí)無(wú)響應(yīng)。這個(gè)東西是DaemonSet部署成本很低但能補(bǔ)齊Dashboard看不到的底層故障。sloop開(kāi)源的小工具可以按時(shí)間線展示Pod的調(diào)度歷史和狀態(tài)變化對(duì)排查某個(gè)Pod為什么被驅(qū)逐特別有用。這些工具不是必選項(xiàng)但加上了之后你會(huì)發(fā)現(xiàn)這套監(jiān)控從能看變成了能查。5.5 從演示走向生產(chǎn)參數(shù)調(diào)整與資源配額演示環(huán)境里使用默認(rèn)參數(shù)沒(méi)問(wèn)題但生產(chǎn)環(huán)境有幾個(gè)硬性要求建議提前調(diào)好。Metrics Server的Deployment需要顯式聲明資源requestsresources: requests: memory: 100Mi cpu: 100m不建議把requests設(shè)得太低否則在內(nèi)存緊張的節(jié)點(diǎn)上Metrics Server可能被判定為不可調(diào)度而監(jiān)控組件恰恰是最不該缺失的。Dashboard的Deployment默認(rèn)資源請(qǐng)求比較保守在大量并發(fā)訪問(wèn)時(shí)會(huì)OOM。我在并發(fā)量高的環(huán)境會(huì)把它調(diào)到memory: 512Mi同時(shí)加上limits防止它把節(jié)點(diǎn)內(nèi)存吃滿。Dashboard的容器主要是渲染和代理API內(nèi)存是主要瓶頸。另外Dashboard的Service默認(rèn)是ClusterIP如果你需要跨集群訪問(wèn)而又不想開(kāi)Ingress可以臨時(shí)改Service類(lèi)型為NodePort但訪問(wèn)時(shí)一定記得加TLS。端口轉(zhuǎn)發(fā)適合排障NodePort適合短期的跨網(wǎng)絡(luò)測(cè)試長(zhǎng)期使用我更傾向于Ingress加內(nèi)部DNS。6. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄6.1 Metrics Server一直不Ready這是部署Metrics Server遇到最多的狀況。Pod狀態(tài)ContainerCreating一直不動(dòng)一般就是鏡像拉不下來(lái)按照鏡像代理的方式處理。如果Pod顯示CrashLoopBackOff先看日志kubectl logs -n kube-system -l app.kubernetes.io/namemetrics-server日志里常見(jiàn)的錯(cuò)誤是unable to fully discover metrics: unable to fetch metrics from node。這種多半是kubelet的證書(shū)問(wèn)題。Kubernetes 1.26以上的集群里kubelet會(huì)生成一個(gè)由集群根CA簽名的服務(wù)證書(shū)但如果你沒(méi)有把根CA配置到kubelet的--tls-cert-file參數(shù)里Metrics Server和kubelet之間會(huì)TLS握手失敗。解決辦法是給Metrics Server加上啟動(dòng)參數(shù)--kubelet-insecure-tls但這只是臨時(shí)繞過(guò)證書(shū)驗(yàn)證。正規(guī)做法是把集群CA加入Metrics Server的信任列表也就是修改Deployment的volume和volumeMount把宿主機(jī)的/etc/kubernetes/pki/ca.crt掛載進(jìn)去。生產(chǎn)環(huán)境我建議用正規(guī)做法--kubelet-insecure-tls能用但本質(zhì)上是關(guān)閉了TLS驗(yàn)證審計(jì)時(shí)不好看。6.2 metrics.k8s.io的ABAC問(wèn)題還有一個(gè)很不起眼但是坑過(guò)人的點(diǎn)如果集群開(kāi)啟了ABAC模式Metrics Server的注冊(cè)可能不會(huì)生效。雖然現(xiàn)在幾乎都是RBAC但老集群偶爾還會(huì)遇到。驗(yàn)證方法是在Master節(jié)點(diǎn)上查API Server的啟動(dòng)參數(shù)看有沒(méi)有--authorization-modeABAC。如果確實(shí)開(kāi)了需要把Metrics Server的ServiceAccount加入ABAC策略文件否則kubectl top會(huì)一直報(bào)metrics.k8s.io is forbidden。不過(guò)這種場(chǎng)景現(xiàn)在比較少見(jiàn)遇到的話基本上是歷史原因短平快的處理方案是建議集群遷移時(shí)切到RBAC模式。6.3 Dashboard登錄后白屏或空白我遇到過(guò)Dashboard能訪問(wèn)但登錄后頁(yè)面空白的情況。排查步驟按照這個(gè)順序來(lái)瀏覽器F12看控制臺(tái)有沒(méi)有報(bào)錯(cuò)。常見(jiàn)的報(bào)錯(cuò)是failed to fetch metrics這種就回去查Metrics Server跟Dashboard本身沒(méi)有關(guān)系。確認(rèn)Token是真正的服務(wù)賬號(hào)Token。新版Kubernetes里如果你用kubectl get secret admin-user-token-xxx -o jsonpath{.data.token}取出來(lái)的Token有些場(chǎng)景因?yàn)?-legacy-service-account-token-clean-up的啟動(dòng)參數(shù)會(huì)被標(biāo)記為無(wú)效Dashboard登錄會(huì)直接失敗。確認(rèn)瀏覽器沒(méi)有攔截跨域請(qǐng)求。Dashboard自身的API請(qǐng)求是從頁(yè)面發(fā)到集群API Server如果中間有代理做了攔截就會(huì)出現(xiàn)白屏。白屏問(wèn)題九成以上都是Token或者M(jìn)etrics API不通Dashboard本身極少掛。6.4 數(shù)值顯示NaN或者負(fù)數(shù)有段時(shí)間我配置了Metrics Server的自定義參數(shù)Dashboard里顯示CPU利用率為NaN排查下來(lái)發(fā)現(xiàn)是抓取間隔調(diào)得太短Metrics Server在API Server做聚合時(shí)累計(jì)的計(jì)算窗口產(chǎn)生了邊界問(wèn)題CPU平均值算出來(lái)是空的。后來(lái)我把配置恢復(fù)默認(rèn)數(shù)值就正常了。內(nèi)存使用量為負(fù)數(shù)的情況多半發(fā)生在你給Pod設(shè)置的limits.memory小于實(shí)際節(jié)點(diǎn)上的Page Cache統(tǒng)計(jì)口徑時(shí)雖然少見(jiàn)但遇上不要緊張懷疑統(tǒng)計(jì)口徑差異而不是組件故障。6.5 端口轉(zhuǎn)發(fā)可以訪問(wèn)但I(xiàn)ngress訪問(wèn)不通這個(gè)區(qū)別很典型。端口轉(zhuǎn)發(fā)是直接走API Server代理如果轉(zhuǎn)發(fā)通了說(shuō)明Dashboard后端本身沒(méi)問(wèn)題。Ingress不通問(wèn)題大多在Ingress Controller的HTTPS后端配置。你可以先關(guān)掉Ingress里的ssl-passthrough改用nginx.ingress.kubernetes.io/backend-protocol: HTTPS并確保證書(shū)Secret里的私鑰和證書(shū)是配套的。還有一種情況是Ingress Controller自己沒(méi)有監(jiān)聽(tīng)443端口檢查Controller的Service里是否暴露了443把它映射到宿主機(jī)端口即可。這類(lèi)網(wǎng)絡(luò)問(wèn)題有個(gè)萬(wàn)能的排查起點(diǎn)在集群內(nèi)curl一下Dashboard Service地址確認(rèn)后端可達(dá)再?gòu)腎ngress Controller所在節(jié)點(diǎn)curl Service地址逐段縮小范圍問(wèn)題很快就定位了。我實(shí)際用了這一套組合很久最大的感觸是它幫我擋掉了大量半夜接到告警但不知道集群怎么了的焦慮。Metrics Server加Dashboard的監(jiān)控能力雖然不算深但覆蓋面剛剛好尤其是對(duì)中小規(guī)模集群從節(jié)點(diǎn)CPU到Pod內(nèi)存再到HPA目標(biāo)用一對(duì)組合就能講清楚集群的大部分故事。踩過(guò)幾次坑之后我現(xiàn)在的習(xí)慣是每次部署完都順手把kubectl top node跑一遍把輸出存下來(lái)當(dāng)作集群初始狀態(tài)的基線。如果以后要繼續(xù)往深走可以在同一套鏈路里再引入Prometheus做長(zhǎng)期存儲(chǔ)和告警但第一步先讓Dashboard上的曲線亮起來(lái)這比什么都有說(shuō)服力。