Kubernetes監控在小米的落地

本文介紹了高可用、持久存儲、可動態調整的Kubernetes監控方案的實現過程。
上篇文章回顧: 記一次kubernetes集羣異常:kubelet鏈接apiserver超時

小米的彈性調度平臺(Ocean)以及容器平臺主要基於開源容器自動化管理平臺kubernetes(簡稱k8s)來提供服務,完善的監控系統提升容器服務的質量的前提。不一樣於傳統物理主機,每一個容器至關於一個主機,致使一臺物理主機上的系統指標數量成本增加,總的監控指標規模至關龐大(經線上統計,每node指標達到10000+)。此外,爲了不重複造輪,須要最大限度的利用公司的監控報警系統,須要把k8s的監控和報警融入其中。在小米現有的基礎設施之上,落地該監控,是一個不小的挑戰。node

當監控趕上K8S

爲了更方便的管理容器,k8s對container進行了封裝,擁有了Pod、Deployment、Namespace、Service等衆多概念。與傳統集羣相比,k8s集羣監控更加複雜:算法

(1)監控維度更多,除了傳統物理集羣的監控,還包括核心服務監控(apiserver, etcd等)、容器監控、Pod監控、Namespace監控等。數據庫

(2)監控對象動態可變,在集羣中容器的銷燬建立十分頻繁,沒法提早預置。json

(3)監控指標隨着容器規模爆炸式增加,如何處理及展現大量監控數據。後端

(4)隨着集羣動態增加,監控系統必須具有動態擴縮的能力。api

除了k8s集羣監控自己的特性外,具體監控方案的實現要考慮公司內部的實際狀況:性能優化

(1)目前彈性調度計算平臺提供的k8s集羣包括:融合雲容器集羣、部分Ocean集羣以及CloudML集羣,擁有十餘個集羣,1000+機器。不一樣k8s集羣的部署方式,網絡模式,存儲方式等不盡相同,監控方案須要兼顧各類差別。bash

(2)Open-Falcon是公司內通用的監控報警系統,有完善的數據收集,展現和報警機制,可是Open-Falcon並不支持k8s這種拉的採集方案。此外,k8s裏的各類資源,有自然的層次關係,這就決定了監控數據的整合須要強大而靈活的聚合能力,Falcon在這些方面不太能知足需求。但咱們並不想重複造輪子,須要最大限度利用公司既有基礎設施,從而節約開發和運維成本。網絡

(3)對於監控的持久化存儲,如何結合公司內的數據庫,實現監控數據的長期存儲,都是須要考慮的問題。架構

現有業界針對k8s監控也有一些成熟的方案:

(1)Heapster/Metrics-Server+ InfluxDB + Grafana

Heapster是k8s原生的集羣監控方案(現已廢棄,轉向metrics-server),從節點上的 cadvisor獲取計算、存儲、網絡等監控數據,而後將這些數據輸出到外部存儲(backend),如InfluxDB,最後再經過相應的UI界面進行可視化展現,如grafana。此方案部署簡單,但採集數據單一,不合適k8s集羣總體監控,只適用於監控集羣中各容器的資源信息,如做爲k8s dashboard的數據展現源。

(2)Exporter+Prometheus+Adapter

Prometheus 是一套開源的系統監控報警框架,具備多維數據模型、靈活強大的查詢語句、性能良好等特色。Prometheus能夠經過各類exporter,如node-exporter、kube-state-metrics、cadivsor等採集監控metrics監控數據,此外Prometheus能夠動態發現k8s集羣中的pod,node等對象。經過Prometheus採集各個維度的數據,進行聚合並提供報警,而後利用adapter能夠將數據寫到遠程儲存中(如OpenTSDB,InfluxDB )等實現持久化存儲。但因爲數據採集可能會有丟失,因此 Prometheus 不適用於對採集數據要 100% 準確的情形,例如實時監控等。

監控方案及演進

初始方案

前期,爲了儘快實現k8s的落地,監控系統藉助Falcon還有內部開發的exporter,僅實現了對於核心監控數據的採集,如Pod的cpu,內存,網絡等資源使用狀況,具體架構以下圖所示。

經過實現cadvisor-exporter採集cadvisor的容器監控數據;kube-state-exporter採集k8s關鍵Pod指標;Falcon-agent採集物理節點數據。初始方案僅採集了核心監控數據,初步實現對核心資源使用狀況的監控,缺少更全面的數據監控,例如apiserver,etcd等。因爲Falcon目前不支持對於容器的監控,因此須要手動實現各類exporter來知足k8s的監控需求。並且監控數據沒有實現持久化存儲,不支持長期查詢。

基於Prometheus的監控系統

因爲初始監控系統的不足,通過調研對比最終選用Prometheus做爲k8s的監控方案,主要考慮一下幾點緣由:

(1)原生支持k8s監控,具備k8s對象服務發現能力,並且k8s的核心組件提供了Prometheus的採集接口

(2)強大的性能,單個Prometheus能夠每秒抓取10萬的metrics,能夠知足必定規模下k8s集羣的監控需求

(3)良好的查詢能力:Prometheus 提供有數據查詢語言 PromQL。PromQL 提供了大量的數據計算函數,大部分狀況下用戶均可以直接經過 PromQL 從 Prometheus 裏查詢到須要的聚合數據。

基於Prometheus的k8s監控系統的架構以下圖所示:

數據源:node-exporter採集物理節點指標;kube-state-metrics採集k8s相關指標,包括資源使用狀況,以及各類對象的狀態信息;cadvisor採集容器相關指標;apiserver, etcd, scheduler, k8s-lvm,gpu等核心組件的監控數據;其餘自定義metrics,經過在pod yaml文件annotations添加 prometheus.io/scrape: "true" 可實現自動抓取提供的metrics。

Prometheus數據處理模塊:Prometheus以Pod方式部署在k8s上,Pod中含有Prometheus、Prom-Reloader。Prometheus負責採集聚合數據;prom-config爲監控的聚合規則與抓取配置,以ConfigMap存儲;Prom-Reloader實現監控配置的熱更新,實時監控配置文件,無需重啓應用便可動態加載最新配置。

存儲後端:Falcon與OpenTSDB。

Open-Falcon是公司統一的監控報警系統,提供了完善的數據採集、報警、展現、歷史數據存儲功能以及權限功能。因爲Falcon設計較早,沒有對於容器相關指標提供監控,而prometheus原生支持了k8s,可是其報警功能只能靜態配置且須要實現與公司相關帳號打通以方便用戶配置監控,且有些k8s的指標,須要暴露給容器用戶。基於此考慮,咱們使用Falcon做爲k8s監控的報警和對外展現平臺。經過實現Falcon-Adapter,將監控數據轉發到Falcon以實現報警與展現。根據k8s服務對象將監控目標分爲多個層次:cluster, node, namespace, deployment, pod,將關鍵報警指標經過Falcon-Agent打到Falcon,用戶可自行在配置報警查看指標。

原生Prometheus的監控數據放在本地(使用tsdb時區數據庫),默認保存15天數據。監控數據不止用於監控與報警,後續的運營分析和精細化運維都須要以這些運營數據做爲基礎,所以須要數據的持久化。在Prometheus社區中也提供了部分讀寫方案,如Influxdb、Graphite、OpenTSDB等。而小米正好有OpenTSDB團隊,OpenTSDB將時序數據存儲在HBase中,咱們公司的HBase也有穩定的團隊支持。基於此經過OpenTSDB爲監控數據提供遠程存儲。實現了OpenTSDB-Adapter,將監控數據轉發到時序數據庫OpenTSDB以實現數據的持久存儲,知足長期查詢以及後期數據分析的須要。

部署方式

系統監控的核心繫統所有經過Deployment/Daemonset形式部署在k8s集羣中,以保證監控服務的可靠性。所有配置文件使用ConfigMap存儲並實現了自動更新。

存儲方式
Prometheus的存儲包括本地存儲與遠程存儲,本地存儲只保存短時間內的監控數據,按照兩個小時爲一個時間窗口,將兩小時內產生的數據存儲在一個塊(Block)中,每個塊中包含該時間窗口內的全部樣本數據(chunks),元數據文件(meta.json)以及索引文件(index)。因爲各集羣提供存儲類型的不行,目前已經實現多種存儲方式的部署包括pvc、lvm、本地磁盤等。

遠程存儲經過實現prometheus的遠程讀寫接口實現對OpenTSDB的操做,方便對於長期數據的查詢。

爲了保持Prometheus的簡單性,Prometheus並無嘗試在自身中解決以上問題,而是經過定義兩個標準接口(remote_write/remote_read),讓用戶能夠基於這兩個接口對接將數據保存到任意第三方的存儲服務中,這種方式在Promthues中稱爲Remote Storage。

如上圖所示,能夠在Prometheus配置文件中指定Remote Write(遠程寫)的URL地址,一旦設置了該配置項,Prometheus將採集到的樣本數據經過HTTP的形式發送給適配器(Adapter)。而用戶則能夠在適配器中對接外部任意的服務。外部服務能夠是真正的存儲系統,公有云的存儲服務,也能夠是消息隊列等任意形式。一樣地,Promthues的Remote Read(遠程讀)也經過了一個適配器實現。在遠程讀的流程當中,當用戶發起查詢請求後,Promthues將向remote_read中配置的URL發起查詢請求(matchers,time ranges),Adapter根據請求條件從第三方存儲服務中獲取響應的數據。同時將數據轉換爲Promthues的原始樣本數據返回給Prometheus Server。當獲取到樣本數據後,Promthues在本地使用PromQL對樣本數據進行二次處理。啓用遠程讀設置後,只在數據查詢時有效,對於規則文件的處理,以及Metadata API的處理都只基於Prometheus本地存儲完成。

遠程存儲現已支持公司內部的Falcon與OpenTSDB,經過Falcon方便用戶查看監控數據以及配置報警。寫到OpenTSDB已實現持久化存儲,而且支持經過Prometheus對其進行遠程讀寫。

目前基於Prometheus的監控方案已在各集羣部署,但隨着集羣規模的增加逐漸暴露出一些問題。

其一,是隨着容器增加監控指標激增,對Falcon-agent與transfer形成必定壓力,導致常常形成Falcon-agent擁堵以及部分監控數據延遲、丟失等問題。在線上測試當經過單個Falcon-agent發送超過150000/m時,常常性出現數據丟失,現已關閉部分監控數據的發送。根本緣由是prometheuse集中的數據聚合和推送,把分散在各集羣的指標匯聚到了一臺主機,從而帶來了超常的壓力。

其二,是在規模較大的集羣,Prometheus佔用CPU與內存資源都較多(下表中爲線上集羣Prometheus的運行狀況),偶爾會出現某些metrics抓取不到的狀況,隨着集羣規模的擴大單個Prometheus將會遇到性能瓶頸。

分區監控方案

針對單個Prometheus監控方案的不足,須要對其進行擴展已知足大規模k8s集羣監控,並適配Falcon系統agent的性能。經過調研,發現Prometheus支持集羣聯邦。這種分區的方式增長了Prometheus自身的可擴展性,同時,也能夠分散對單個Falcon agent的壓力。

聯邦功能是一個特殊的查詢接口,容許一個prometheus抓取另外一個prometheus的metrics,已實現分區的目的。以下所示:

常見分區兩種方式:

其一是功能分區,聯邦集羣的特性能夠幫助用戶根據不一樣的監控規模對Promthues部署架構進行調整,能夠在各個數據中心中部署多個Prometheus Server實例。每個Prometheus Server實例只負責採集當前數據中心中的一部分任務(Job),例如能夠將不一樣的監控任務分配到不一樣的Prometheus實例當中,再由中心Prometheus實例進行聚合。

其二是水平擴展,極端狀況下,單個採集任務的Target數也變得很是巨大。這時簡單經過聯邦集羣進行功能分區,Prometheus Server也沒法有效處理時。這種狀況只能考慮繼續在實例級別進行功能劃分。將同一任務的不一樣實例的監控數據採集任務劃分到不一樣的Prometheus實例。經過relabel設置,咱們能夠確保當前Prometheus Server只收集當前採集任務的一部分實例的監控指標。

針對k8s的實際狀況,分區方案架構以下:

Prometheus分區包括master Prometheus 與 slave Prometheus以及 kube state Prometheus:因爲大量指標的採集來源於node上的服務,如kubelet, node-exporter, cadvisor等是以node爲單位採集的,因此按照node節點來劃分不一樣job,slave Prometheus 按照node切片採集node,pod級別數據;

kube-state-metrics暫時沒法切片,單獨做爲一個kube-state Prometheus,供master Prometheus採集;其餘etcd, apiserver,自定義指標等可經過master Prometheus直接採集。

Prometheus master對於其餘Prometheus slave的抓取可經過以下配置:

- job_name: federate-slave  honor_labels: true  metrics_path: '/federate'  params:    'match[]':      - '{__name__=~"pod:.*|node:.*"}'  kubernetes_sd_configs:  - role: pod    namespaces:      names:      - kube-system  relabel_configs:  - source_labels:    - __meta_kubernetes_pod_label_app    action: keep    regex: prometheus-slave.*複製代碼

Prometheus slave的對於抓取任務的分區經過Prometheus提供的hashmod方法來實現:

- job_name: kubelet  scheme: https  kubernetes_sd_configs:  - role: node    namespaces:      names: []  tls_config:    insecure_skip_verify: true  relabel_configs:  - source_labels: []    regex: __meta_kubernetes_node_label_(.+)    replacement: "$1"    action: labelmap  - source_labels: [__meta_kubernetes_node_label_kubernetes_io_hostname]    modulus:       ${modulus}    target_label:  __tmp_hash    action:        hashmod  - source_labels: [__tmp_hash]    regex:         ${slaveId}    action:        keep複製代碼

部署方式

master Prometheus 與 kube-state Prometheus經過deployment部署。slave Prometheus可有多個pod,但因爲每一個pod的配置不一樣(配置中的${slaveId}不一樣),每一個slave prometheus須要在配置中體現分區編號,而原生的deployment/statefulset/daemonset都不支持同一Pod模板掛載不一樣的ConfigMap配置。爲了方便管理Slave Prometheus經過statefulset來部署slave,因爲statefulset會將每一個pod按順利編號如slave-0,slave-1等。經過Prom-Reloader得到到Pod名稱,持續監聽Prometheus配置變化,而後生成帶有編號的配置以區分不一樣的分區模塊。

測試驗證

測試包括兩方面,一是針對分區後的監控方案進行功能測試是否符合預期,二是對於其性能進行測試

在功能測試中,驗證分區方案的聚合規則正常,特別對於分區先後的數據進行校驗,經過對一週內的數據進行對比,取一小時內平均的差值比率,以下圖:

經統計,超過95%的時間序列對比偏差在1%之內,個別指標瞬時波動較大(如網絡使用率),但隨着時間增長會抵消差別。

在性能測試中,針對不一樣分區監控不一樣負載下進行測試,驗證其性能情況。

在測試集羣上建立1000個虛擬node,建立不一樣數量pod測試Prometheus分區性能:

對於Prometheus master與Prometheus kube-state在1分鐘抓取時間內最多可支持8w pod,主要瓶頸在於kube-state-metrics隨着pod增長,數據量激增,一次抓取耗時不斷增加。

對於Prometheus slave因爲採集部分數據,壓力較小,單個Prometheus可抓取超過400個節點(60 pod/node)。以下圖所示在開啓remote write後抓取時間不斷增長,後續將不斷增長Remote-Storage-Adapter的性能。

通過在k8s測試集羣驗證,Prometheus分區監控架構最多支持8w的pod,能夠知足預期集羣增加需求。

展望

目前分區監控方案已在部分集羣部署,具備高可用、持久存儲、可動態調整等特色。另外,咱們將來將持續改進:實現監控的自動擴容,針對kube-state-metrics的性能優化(目前不支持分區);在部署方式上,藉助prometheus-operator與helm等實現更簡潔的配置管理與部署;在監控數據的利用上,能夠應用特定算法對數據進行深度挖掘以提供有價值的信息,如利用監控數據提供擴容預測,尋找合適的擴容時機。經過不斷優化,以確保更好地爲k8s提供穩定可靠智能的監控服務。


本文首發於公衆號「小米雲技術」,轉載請註明做者及出處,點擊查看原文

相關文章
相關標籤/搜索