這篇文章主要講解了“怎么用Prometheus監(jiān)控十萬container的Kubernetes集群”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么用Prometheus監(jiān)控十萬container的Kubernetes集群”吧!
成都創(chuàng)新互聯(lián)是專業(yè)的大安網(wǎng)站建設公司,大安接單;提供成都網(wǎng)站建設、網(wǎng)站設計,網(wǎng)頁設計,網(wǎng)站設計,建網(wǎng)站,PHP網(wǎng)站建設等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行大安網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
Prometheus依靠其強勁的單機性能,靈活的PromSQL,活躍的社區(qū)生態(tài),逐漸成為云原生時代最核心的監(jiān)控組件,被全球各大產(chǎn)商用于監(jiān)控他們的核心業(yè)務。
然而,面對大規(guī)模監(jiān)控目標(數(shù)千萬series)時,由于原生Prometheus只有單機版本,不提供集群化功能,開發(fā)人員不得不通過不斷增加機器的配置來滿足Prometheus不斷上漲的內(nèi)存。
我們對單機Prometheus進行的壓測,用以探測單個Prometheus分片的合理負載,壓測的目標有兩個。
確定target數(shù)目對Prometheus負載的關(guān)系
確定series數(shù)目和Prometheus負載的關(guān)系
我們保持總series為100萬不變, 通過改變target個數(shù),觀察Prometheus負載變動。 壓測結(jié)果
target數(shù)量 | CPU (core) | mem (GB) |
---|---|---|
100 | 0.17 | 4.6 |
500 | 0.19 | 4.2 |
1000 | 0.16 | 3.9 |
5000 | 0.3 | 4.6 |
從表中我們發(fā)現(xiàn)target數(shù)目的改動對Prometheus負載的影響并不是強相關(guān)的。在target數(shù)目增長50倍的情況下,CPU消耗有小量增長,但是內(nèi)存幾乎不變。
我們保持target數(shù)目不變,通過改變總series數(shù),觀察Prometheus的負載變動。
壓測結(jié)果
series數(shù)量 (萬) | CPU (core) | mem (GB) | 查詢1000 series 15m數(shù)據(jù)(s) |
---|---|---|---|
100 | 0.191 | 3.15 | 0.2 |
300 | 0.939 | 20.14 | 1.6 |
500 | 2.026 | 30.57 | 1.5 |
從表中,Prometheus的負載受到series的影響較大,series越多,資源消耗越大。
當series數(shù)據(jù)超過300萬時,Prometheus內(nèi)存增長較為明顯,需要使用較大內(nèi)存的機器來運行。
壓測過程中,我們使用了工具去生成預期數(shù)目的series,工具生成的series每個label的長度及值的長度都較小,固定為10個字符左右。我們的目的是觀察相對負載變化,實際生產(chǎn)中由于label長度不同,服務發(fā)現(xiàn)機制的消耗不同,相同的series數(shù)目所消耗的負載會比壓測中高不少。
針對單機Prometheus在大規(guī)模數(shù)據(jù)監(jiān)控時的性能瓶頸問題,社區(qū)目前已經(jīng)存在一些分片化方案,主要包括以下幾種。
Prometheus官方支持通過Relabel機制,在配置文件中,對采集上來的數(shù)據(jù)進行hash,通過在不同Prometheus實例的配置文件中指定不同的moduleID來進行分片化,然后通過聯(lián)邦,Thanos等方式將數(shù)據(jù)進行統(tǒng)一匯總,如下圖所示,讀者也可以直接參考【官方文檔】。
還有一種方法是根據(jù)業(yè)務進行job層面的分割,不同Prometheus使用完全獨立的采集配置,其中包含了不同的job,。
無論是hash_mod的方式,還是配置文件分割的方式,其本質(zhì)都是將數(shù)據(jù)切分到多個采集配置中,由不同Prometheus進行采集。兩者都存在以下幾個缺點。
**對預監(jiān)控數(shù)據(jù)要有所了解:**使用上述方法的前提是使用者必須對監(jiān)控對象會上報的數(shù)據(jù)有所了解,例如必須知道監(jiān)控對象會上報某個用于hash_mod的label,或者必須知道不同job的整體規(guī)模,才能對job進行劃分。
**實例負載不均衡:**雖然上述方案預期都是希望將數(shù)據(jù)打散到不同Prometheus實例上,但實際上通過某些label的值進行hash_mod的,或者干脆按job進行劃分的方式并不能保證每個實例最終所采集的series數(shù)是均衡的,實例依舊存在內(nèi)存占用過高的風險。
**配置文件有侵入:**使用者必須對原配置文件進行改造,加入Relabel相關(guān)配置,或者將一份配置文件劃分成多份,由于配置文件不再單一,新增,修改配置難度大大增加。
**無法動態(tài)擴縮容:**上述方案中的由于配置是根據(jù)實際監(jiān)控目標的數(shù)據(jù)規(guī)模來特殊制定的,并沒有一種統(tǒng)一的擴縮容方案,可以在數(shù)據(jù)規(guī)模增長時增加Prometheus個數(shù)。當然,用戶如果針對自己業(yè)務實際情況編寫擴縮容的工具確實是可以的,但是這種方式并不能在不同業(yè)務間復用。
**部分API不再正常:**上述方案將數(shù)據(jù)打散到了不同實例中,然后通過聯(lián)邦或者Thanos進行匯總,得到全局監(jiān)控數(shù)據(jù),但是在不額外處理的情況下會導致部分Prometheus 原生API無法得到正確的值,最典型的是/api/v1/targets ,上述方案下無法得到全局targets值。
針對上述問題,我們希望設計一種無侵入的集群化方案,它對使用者表現(xiàn)出來的,是一個與原生Prometheus配置文件一致,API兼容,可擴縮容的虛擬Prometheus。具體而言,我們有以下設計目標。
**無侵入,單配置文件:**我們希望使用者看到的,修改的都是一份原生的配置文件,不用加任何特殊的配置。
無需感知監(jiān)控對象:我們希望使用者不再需要預先了解采集對象,不參與集群化的過程。
**實例負載盡可能均衡:**我們希望能根據(jù)監(jiān)控目標的實際負載來劃分采集任務,讓實例盡可能均衡。
**動態(tài)擴縮容:**我們希望系統(tǒng)能夠根據(jù)采集對象規(guī)模的變化進行動態(tài)擴縮容,過程中數(shù)據(jù)不斷點,不缺失。
**兼容核心PrometheusAPI:**我們希望一些較為核心的API,如上邊提到的/api/v1/target接口是正常的。
Kvass由多個組件構(gòu)成,下圖給出了Kvass的架構(gòu)圖,我們在架構(gòu)圖中使用了Thanos,實際上Kvass并不強依賴于Thanos,可以換成其他TSDB。
Kvass sidecar:用于接收Coordinator下發(fā)的采集任務,生成新的配置文件給Prometheus,也服務維護target負載情況。
Kvass coordinator:該組件是集群的中心控制器,負責服務發(fā)現(xiàn),負載探測,targets下發(fā)等。
Thanos 組件:圖中只使用了Thanos sidecar與Thanos query,用于對分片的數(shù)據(jù)進行匯總,得到統(tǒng)一的數(shù)據(jù)視圖。
Kvass coordinaor 首先會代替Prometheus對采集目標做服務發(fā)現(xiàn),實時獲得需要采集的target列表。
針對這些target,Kvass coordinaor會負責對其做負載探測,評估每個target的series數(shù),一旦target負載被探測成功,Kvass coordinaor 就會在下個計算周期將target分配給某個負載在閾值以下的分片。
Kvass coordinaor 還負責對分片集群做擴縮容。
Kvass coordinaor引用了原生Prometheus的服務發(fā)現(xiàn)代碼,用于實現(xiàn)與Prometheus 100%兼容的服務發(fā)現(xiàn)能力,針對服務發(fā)現(xiàn)得到的待抓取targets,Coordinaor會對其應用配置文件中的relabel_configs進行處理,得到處理之后的targets及其label集合。服務發(fā)現(xiàn)后得到的target被送往負載探測模塊進行負載探測。
負載探測模塊從服務發(fā)現(xiàn)模塊獲得處理之后的targets,結(jié)合配置文件中的抓取配置(如proxy,證書等)對目標進行抓取,隨后解析計算抓取結(jié)果,獲得target的series規(guī)模。
負載探測模塊并不存儲任何抓取到的指標數(shù)據(jù),只記錄target的負載,負載探測只對target探測一次,不維護后續(xù)target的負載變化,長期運行的target的負載信息由Sidecar維護,我們將在后面章節(jié)介紹。
在Prometheus單機性能瓶頸那一節(jié),我們介紹過Prometheus的內(nèi)存和series相關(guān),確切來說,Prometheus的內(nèi)存和其head series直接相關(guān)。Prometheus 會將最近(默認為2小時)采集到的數(shù)據(jù)的series信息緩存在內(nèi)存中,我們?nèi)绻芸刂坪妹總€分片內(nèi)存中head series的數(shù)目,就能有效控制每個分片的內(nèi)存使用量,而控制head series實際就是控制分片當前采集的target列表。
基于上邊的思路,Kvass coordinaor會周期性的對每個分片當前采集的target列表進行管理:分配新target,刪除無效target。
在每個周期,Coordinaor會首先從所有分片獲得當前運行狀態(tài),其中包括分片當前內(nèi)存中的series數(shù)目及當前正在抓取的target列表。隨后針對從服務發(fā)現(xiàn)模塊得到的全局target信息進行以下處理
如果該target已經(jīng)被某個分片抓取,則繼續(xù)分配給他,分片的series數(shù)不變。
如果該target沒有任何分片抓取,則從負載探測模塊獲得其series(如果還未探測完則跳過,下個周期繼續(xù)),從分片中挑一個目前內(nèi)存中series加上該target的series后依然比閾值低的,分配給他。
如果當前所有分片沒法容納所有待分配的targets,則進行擴容,擴容數(shù)量與全局series總量成正比。
在系統(tǒng)運行過程中,target有可能會被刪除,如果某個分片的target被刪除且超過2小時,則該分片中的head series就會降低,也就是出現(xiàn)了部分空閑,因為target分配到了不同分片,如果有大量target被刪除,則會出現(xiàn)很多分片的內(nèi)存占用都很低的情況,這種情況下,系統(tǒng)的資源利用率很低,我們需要對系統(tǒng)進行縮容。
當出現(xiàn)這種情時,Coordinaor會對target進行遷移,即將序號更大的分片(分片會從0進行編號)中的target轉(zhuǎn)移到序號更低的分片中,最終讓序號低的分片負載變高,讓序號高的分片完全空閑出來。如果存儲使用了thanos,并會將數(shù)據(jù)存儲到cos中,則空閑分片在經(jīng)過2小時候會刪除(確保數(shù)據(jù)已被傳到cos中)。
Kvass的分片當前只支持以StatefulSet方式部署。
Coordinator將通過label selector來獲得所有分片StatefulSet,每個StatefulSet被認為是一個副本,StatefulSet中編號相同的Pod會被認為是同一個分片組,相同分片組的Pod將被分配相同的target并預期有相同的負載。
上文提到Coordinator根據(jù)配置文件做了服務發(fā)現(xiàn),得到了target列表,所以Coordinator實際上可以得到/api/v1/targets接口所需要的返回結(jié)果集合,但是由于Coordinator只做了服務發(fā)現(xiàn),并不進行實際采集,所以target的采集狀態(tài)(例如健康狀態(tài),上一次采集時間等)都無法直接得知。
當Coordinator接收到/api/v1/targets請求時,他會基于服務發(fā)現(xiàn)得到的target集合,結(jié)合向Sidecar(如果target已分配)或向探測模塊(target還未分配)詢問target采集狀態(tài),綜合后將正確的/api/v1/targets結(jié)果返回。
上一節(jié)介紹了Kvass coordinaor的基本功能,要想系統(tǒng)正常運行,還需要Kvass sidecar的配合,其核心思想是將配置文件中所有服務發(fā)現(xiàn)模式全部改成static_configs并直接將已經(jīng)relabel過的target信息寫入配置中,來達到消除分片服務發(fā)現(xiàn)和relabel行為,只采集部分target的效果。
每個分片都會有一個Kvass sidecar,其核心功能包括從Kvass coordinator接受本分片負責的target列表,生成新的配置文件給該分片的Prometheus使用。另外,Kvass sidecar還會劫持抓取請求,維護target最新負載。Kvass sidecar還作為PrometheusAPI的網(wǎng)關(guān),修正部分請求結(jié)果。
Coordinaor經(jīng)過服務發(fā)現(xiàn),relabel及負載探測后,會將target分配給某個分片,并將target信息下發(fā)給Sidecar,包括
target的地址,
target預估的series值
target的hash值
處理完relabel之后的label集合。
Sidecar根據(jù)從Coordinator得到的target信息,結(jié)合原始配置文件,生成一個新的配置文件給Prometheus使用,這個新的配置文件做了如下改動。
將所有服務發(fā)現(xiàn)機制改為static_configs模式,并直接寫入target列表,每個target包含經(jīng)過relabel之后的label值
由于現(xiàn)在target已經(jīng)relabel過了,所以刪除job配置中的relabel_configs項,但是依舊保留metrics_rebale_configs
將target的label中的scheme字段全部替換成http,并將原schme以請求參數(shù)的形式加入到label集合中
將target的job_name以請求參數(shù)的形式加入到label集合中* 注入proxy_url將所有抓取請求代理到Sidecar
我們來看一個例子,假如原來的配置是一個kubelet的采集配置
global: evaluation_interval: 30s scrape_interval: 15s scrape_configs: - job_name: kubelet honor_timestamps: true metrics_path: /metrics scheme: https kubernetes_sd_configs: - role: node bearer_token: xxx tls_config: insecure_skip_verify: true relabel_configs: - separator: ; regex: __meta_kubernetes_node_label_(.+) replacement: $1 action: labelmap
通過注入將生成一個新的配置文件
global: evaluation_interval: 30s scrape_interval: 15s scrape_configs: - job_name: kubelet honor_timestamps: true metrics_path: /metrics scheme: https proxy_url: http://127.0.0.1:8008 # 所有抓取請求代理到Sidecar static_configs: - targets: - 111.111.111.111:10250 labels: __address__: 111.111.111.111:10250 __metrics_path__: /metrics __param__hash: "15696628886240206341" __param__jobName: kubelet __param__scheme: https # 保存原始的scheme __scheme__: http # 設置新的scheme,這將使得代理到Sidecar的抓取請求都是http請求 # 以下是經(jīng)過relabel_configs處理之后得到的label集合 beta_kubernetes_io_arch: amd64 beta_kubernetes_io_instance_type: QCLOUD beta_kubernetes_io_os: linux cloud_tencent_com_auto_scaling_group_id: asg-b4pwdxq5 cloud_tencent_com_node_instance_id: ins-q0toknxf failure_domain_beta_kubernetes_io_region: sh failure_domain_beta_kubernetes_io_zone: "200003" instance: 172.18.1.106 job: kubelet kubernetes_io_arch: amd64 kubernetes_io_hostname: 172.18.1.106 kubernetes_io_os: linux
上邊新生成的配置文件是Prometheus真正使用的配置文件,Sidecar通過Coordinator下發(fā)的target列表來生成配置,就可以讓Prometheus有選擇性得進行采集。
在上邊的配置生成中,我們會將proxy注入到job的配置中,并且target的label中,scheme會被設置成http,所以Prometheus所有的抓取請求都會被代理到Sidecar,之所以要這么做,是因為Sidecar需要維護每個target新的series規(guī)模,用于Coordinator查閱后作為target遷移的參考。
從上邊配置生成我們可以看到,有以下幾個額外的請求參數(shù)會被一并發(fā)送到Sidecar
hash:target的hash值,用于Sidecar識別是哪個target的抓取請求,hash值由Coordinator根據(jù)target的label集合進行計算獲得并傳遞給Sidecar。
jobName:是哪個job下的抓取請求,用于Sidecar根據(jù)原配置文件中job的請求配置(如原proxy_url,證書等)對抓取目標發(fā)起真正的請求。
scheme:這里的scheme是target通過relabel操作之后最終得到的協(xié)議值,雖然在job配置文件中已經(jīng)有scheme字段,但Prometheus配置文件依舊支持通過relabel指定某個target的請求協(xié)議。在上述生成新配置過程中,我們將真實的scheme保存到這個參數(shù)里,然后將scheme全部設置成http。
有了上述幾個參數(shù),Sidecar就可以對抓取目標發(fā)起正確的請求,并得到監(jiān)控數(shù)據(jù),在統(tǒng)計的target這次抓取的series規(guī)模后,Sidecar會將監(jiān)控數(shù)據(jù)拷貝一份給Prometheus。
由于Sidecar的存在,部分發(fā)往Prometheus的API請求需要被特殊處理,包括
/-/reload:由于Prometheus真正使用的配置文件由Sidecar生成,針對該接口,需要由Sidecar去處理并在處理成功后調(diào)用Prometheus的/-/reload接口。
/api/v1/status/config:該接口需要由Sidecar處理并把原配置文件返回。
其他接口直接發(fā)往Prometheus。
由于我們將采集目標分散到了不同分片中,導致每個分片的數(shù)據(jù)都只是全局數(shù)據(jù)的一部分,所以我們需要使用額外的組件來將所有數(shù)據(jù)進行匯總并去重(多副本的情況下),得到全局數(shù)據(jù)視圖。
thanos是一個非常好的方案,通過加入thanos組件,可以很方便得得到kvass集群的全局數(shù)據(jù)視圖。當然我們也可以通過加入remote writer配置來使用其他TSDB方案,例如influxdb,M3等等。
這一節(jié)我們通過一個部署例子,來直觀感受一下Kvass的效果,相關(guān)yaml文件可以在這里找到https://github.com/tkestack/kvass/tree/master/examples 讀者可以將項目clone到本地,并進入examples。
git clone https://github.com/tkestack/kvass.git cd kvass/examples
我們提供了一個metrics數(shù)據(jù)生成器,可以指定生成一定數(shù)量的series,在本例子中,我們將部署6個metrics生成器副本,每個會生成10045 series (其中45 series為golang的metrics)。
kubectl create -f metrics.yaml
現(xiàn)在我們部署基于Kvass的Prometheus集群,用以采集這6個metrics生成器的指標。
首先我們部署rbac相關(guān)配置
kubectl create -f kvass-rbac.yaml
接著部署一個Prometheus config文件,這個文件就是我們的原始配置,我們在這個配置文件中,使用kubernetes_sd來做服務發(fā)現(xiàn)
kubectl create -f config.yaml
配置如下
global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: custom scrape_configs: - job_name: 'metrics-test' kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name] regex: metrics action: keep - source_labels: [__meta_kubernetes_pod_ip] action: replace regex: (.*) replacement: ${1}:9091 target_label: __address__ - source_labels: - __meta_kubernetes_pod_name target_label: pod
現(xiàn)在我們來部署Kvass coordinator
kubectl create -f coordinator.yaml
我們在Coordinator的啟動參數(shù)中設置每個分片的最大head series數(shù)目不超過30000
--shard.max-series=30000
我們現(xiàn)在就可以部署帶有Kvass sidecar的Prometheus了,這里我們只部署單個副本
kubectl create -f prometheus-rep-0.yaml
為了得到全局數(shù)據(jù),我們需要部署一個thanos-query
kubectl create -f thanos-query.yaml
根據(jù)上述計算,監(jiān)控目標總計6個target, 60270 series,根據(jù)我們設置每個分片不能超過30000 series,則預期需要3個分片。
我們發(fā)現(xiàn),Coordinator成功將StatefulSet的副本數(shù)改成了3。
我們看下單個分片內(nèi)存中的series數(shù)目,發(fā)現(xiàn)只有2個target的量
我們再通過thanos-query來查看全局數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)是完整的(其中metrics0為指標生成器生成的指標名)
騰訊云容器團隊在Kvass的設計思想上進一步優(yōu)化,構(gòu)建了高性能支持多集群云原生監(jiān)控服務,產(chǎn)品目前已正式公測。
這一節(jié)我們就直接使用云原生監(jiān)控服務來監(jiān)控一個規(guī)模較大的真實集群,測試一下Kvass監(jiān)控大集群的能力。
我們關(guān)聯(lián)的集群規(guī)模大致如下
1060個節(jié)點
64000+ Pod
96000+ container
我們直接使用云原生監(jiān)控服務在關(guān)聯(lián)集群默認添加的采集配置,目前已包含了社區(qū)主流的監(jiān)控指標:
kube-state-metrics
node-exporer
kubelet
cadvisor
kube-apiserver
kube-scheduler
kube-controler-manager
總計3400+target, 2700+萬series
總計擴容了17個分片
每個分片series穩(wěn)定在200w以下
每個分片消耗內(nèi)存在6-10G左右
云原生監(jiān)控所提供的默認Grafana面板也能正常拉取
targets列表也能正常拉取
值得一提的是,云原生監(jiān)控服務不僅支持監(jiān)控單個大規(guī)模集群,還可以用同個實例監(jiān)控多個集群,并支持采集和告警模板功能,可一鍵將采集告警模板下發(fā)至各地域各個集群,徹底告別了每個集群重復添加配置的問題。
感謝各位的閱讀,以上就是“怎么用Prometheus監(jiān)控十萬container的Kubernetes集群”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對怎么用Prometheus監(jiān)控十萬container的Kubernetes集群這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!