使用 Thanos 集中管理多 Prometheus 實(shí)例數(shù)據(jù)
1. 監(jiān)控的分層

如上圖,在建設(shè)監(jiān)控系統(tǒng)時(shí),會采用兩種策略:
分層監(jiān)控。IaaS、MySQL 中間件、App 層監(jiān)控分開的好處是,系統(tǒng)之間具有高可用性、容錯(cuò)性。當(dāng) App 層監(jiān)控?zé)o法工作時(shí),IaaS 層監(jiān)控立馬就會體現(xiàn)出來。 長短期指標(biāo)分離。短期指標(biāo)用來提供給告警系統(tǒng)高頻查詢近期數(shù)據(jù),長期指標(biāo)用來提供給人查詢時(shí)間跨度更大的數(shù)據(jù)集。
這里將其統(tǒng)稱為監(jiān)控的分層策略,只不過一個(gè)是以基礎(chǔ)設(shè)施維度的分層,一個(gè)是以時(shí)間維度的分層。
2. 現(xiàn)狀與選型
目前的狀況是: 沒有進(jìn)行監(jiān)控的長短期分層,共用一套 Prometheus。查詢長周期指標(biāo)時(shí),Prometheus 所在服務(wù)器內(nèi)存、CPU 使用率飆升,甚至導(dǎo)致監(jiān)控、告警服務(wù)不可用。
原因在于兩點(diǎn):
查詢長周期數(shù)據(jù)時(shí),Prometheus 會將大量數(shù)據(jù)載入內(nèi)存 Prometheus 載入的不是降采樣數(shù)據(jù)
查詢的范圍越大,需要的內(nèi)存就越多。在另外一個(gè)生產(chǎn)的方案中,我們采用 VictoriaMetrics 單機(jī)版作為遠(yuǎn)端存儲,部署的內(nèi)存高達(dá) 128 GB 。同時(shí),這種方式下還存在丟數(shù)據(jù)的情況。
而 Prometheus Federation 的方式,只是解決了將多個(gè) Prometheus 聚合起來,并沒有提供抽樣的能力,不能加快長期指標(biāo)的查詢,不適用于當(dāng)前遠(yuǎn)端存儲的場景。
最后看到 Thanos Compact 組件能夠?qū)χ笜?biāo)數(shù)據(jù)進(jìn)行壓縮和降采樣,決定嘗試使用 Thanos 作為目前多個(gè) Prometheus 遠(yuǎn)端存儲使用。
3. Thanos 的幾種部署方式
3.1 基礎(chǔ)組件
Query, 實(shí)現(xiàn)了 Prometheus API,對外提供與 Prometheus 一致的查詢接口 Sidecar, 用于連接 Prometheus,提供 Query 查詢接口、也可以上報(bào)數(shù)據(jù) Store Gateway, 訪問放在對象存儲的指標(biāo)數(shù)據(jù) Compact, 壓縮采樣、清理對象存儲中的數(shù)據(jù) Receive, 接收 Prometheus Remote Write 的數(shù)據(jù) Ruler, 配置和管理告警規(guī)則
3.2 Receive 模式

Receive 模式下,需要在每一個(gè) Prometheus 實(shí)例中配置 remote write 將數(shù)據(jù)上傳給 Thanos。此時(shí),由于實(shí)時(shí)數(shù)據(jù)全部都存儲到了 Thanos Receiver,因此不需要 Sidecar 組件即可完成查詢。
優(yōu)勢:
數(shù)據(jù)集中 Prometheus 無狀態(tài) 只需要暴露 Receiver 給 Prometheus 訪問
缺點(diǎn):
Receiver 承受大量 Prometheus 的 remote write 寫入
3.3 Sidecar 模式

Sidecar 模式下,在每一個(gè) Prometheus 實(shí)例旁添加一個(gè) Thanos Sidecar 組件,以此來實(shí)現(xiàn)對 Prometheus 的管理。主要有兩個(gè)功能:
接受 Query 組件的查詢請求。在 Thanos 查詢短期數(shù)據(jù)時(shí),請求會轉(zhuǎn)到 Sidecar。 上傳 Prometheus 的短期指標(biāo)數(shù)據(jù)。默認(rèn)每兩個(gè)小時(shí),創(chuàng)建一個(gè)塊,上傳到對象存儲。
優(yōu)勢:
集成容易,不需要修改原有配置
缺點(diǎn):
近期數(shù)據(jù)需要 Query 與 Sidecar 之間網(wǎng)絡(luò)請求完成,會增加額外耗時(shí) 需要 Store Gateway 能訪問每個(gè) Prometheus 實(shí)例
4. 部署 Thanos
4.1 部署一個(gè) Minio
請參考文檔: Jenkins 中的構(gòu)建產(chǎn)物與緩存[1]
安裝完成之后,請根據(jù)文檔中的配置進(jìn)行測試,確保 Minio 服務(wù)正常工作。
4.2 在 Minio 上創(chuàng)建一個(gè)名為 thanos 的 Bucket
如下圖:

4.3 檢查 Prometheus 版本符合 Thanos 要求
目前 Thanos 要求 Prometheus 版本最好不低于 v2.13。
4.4 部署 Thanos
確保 Kubernetes 集群上有默認(rèn)的存儲可用
kubectl?get?sc
NAME?????????????????????????PROVISIONER????????RECLAIMPOLICY???VOLUMEBINDINGMODE??????ALLOWVOLUMEEXPANSION???AGE
openebs-device???????????????openebs.io/local???Delete??????????WaitForFirstConsumer???false??????????????????4d5h
openebs-hostpath?(default)???openebs.io/local???Delete??????????WaitForFirstConsumer???false??????????????????4d5h
新建一個(gè)命名空間 thanos
kubectl?create?ns?thanos
部署 Thanos
git?clone?https://github.com/shaowenchen/demo
修改 demo/objectstorage.yaml 文件中的 Minio 訪問地址。然后創(chuàng)建 Thanos 相關(guān)負(fù)載:
kubectl?apply?-f?./demo/thanos-0.25/
查看相關(guān)負(fù)載
kubectl?-n?thanos?top?pod
NAME???????????????????????????CPU(cores)???MEMORY(bytes)
thanos-compact-0???????????????1m???????????30Mi
thanos-query-7c745f5d7-svlgn???2m???????????76Mi
thanos-receive-0???????????????1m???????????15Mi
thanos-rule-0??????????????????1m???????????18Mi
thanos-store-0?????????????????1m???????????55Mi
部署 Thanos 消耗的資源很少。
4.5 訪問 Thanos Query
查看 Thanos 相關(guān)服務(wù)的端口
kubectl?-n?thanos?get?svc
NAME?????????????TYPE????????CLUSTER-IP??????EXTERNAL-IP???PORT(S)???????????????????????????AGE
thanos-compact???ClusterIP???10.233.47.253???????????10902/TCP?????????????????????????11h
thanos-query?????NodePort????10.233.45.138???????????10901:32180/TCP,9090:32612/TCP????11h
thanos-receive???ClusterIP???None????????????????????10902/TCP,19291/TCP,10901/TCP?????11h
thanos-rule??????ClusterIP???None????????????????????10901/TCP,10902/TCP???????????????11h
thanos-store?????NodePort????10.233.41.159???????????10901:30901/TCP,10902:31426/TCP???10h
訪問 Thanos Query 頁面
thanos-query 在 9090 端口提供 http 訪問入口,因此這里通過主機(jī) IP:32612 端口訪問 Query 組件提供的頁面。

5. 給 Prometheus 添加 Thanos Sidecar
Sidecar 模式對 Thanos 配置要求更低,而 Receiver 模式需要不停地接受來自眾多 Prometheus 的 Remote Write,這里出于成本考慮選擇 Sidecar 模式。
5.1 在 Prometheus 所在命名空間新增 S3 訪問憑證
cat?<apiVersion:?v1
kind:?Secret
metadata:
??name:?thanos-objectstorage
??namespace:?minitor
type:?Opaque
stringData:
??objectstorage.yaml:?|
????type:?S3
????config:
????????bucket:?"thanos"
????????endpoint:?"0.0.0.0:9000"
????????insecure:?true
????????access_key:?"minioadmin"
????????secret_key:?"minioadmin"
EOF
這里直接使用的是管理員賬戶,如果是生產(chǎn)上,應(yīng)該單獨(dú)創(chuàng)建一個(gè)賬戶用于 Thanos 對 Minio 的使用。
5.2 給 Prometheus 添加額外的 Label 標(biāo)記實(shí)例
通過在 Prometheus 中添加 external_labels 可以給每個(gè) Prometheus 實(shí)例全局添加一個(gè)額外的標(biāo)簽,用于唯一標(biāo)記一個(gè)實(shí)例。
編輯配置文件
kubectl?-n?monitor?edit?cm?prometheus-server
添加如下內(nèi)容
??prometheus.yml:?|
????global:
??????external_labels:
????????cluster:?dev
這里添加了一個(gè)名為 cluster=dev 的標(biāo)簽。所有該 Prometheus 實(shí)例上報(bào)的指標(biāo)都會帶上此標(biāo)簽,方便查詢過濾
5.3 修改 Prometheus 啟動參數(shù)關(guān)閉壓縮
編輯 Prometheus 部署文件
有的是用 Deployment,有的是用 StatefulSet 部署,都需要修改 Prometheus 的啟動參數(shù)
kubectl?-n?monitor?edit?deploy?prometheus-server
修改 tsdb 存儲塊最大、最小值相等
????????-?--storage.tsdb.max-block-duration=2h
????????-?--storage.tsdb.min-block-duration=2h
????????image:?quay.io/prometheus/prometheus:v2.31.1
storage.tsdb.min-block-duration 和 storage.tsdb.max-block-duration 相等,才能保障 Prometheus 關(guān)閉了本地壓縮,避免壓縮時(shí),Thanos 上傳失敗。
5.4 給 Prometheus 添加 Thanos Sidecar
編輯 Prometheus 部署文件
kubectl?-n?monitor?edit?deploy?prometheus-server
新增如下容器
??????-?args:
????????-?sidecar
????????-?--log.level=debug
????????-?--tsdb.path=/data
????????-?--prometheus.url=http://127.0.0.1:9090
????????-?--objstore.config-file=/etc/objectstorage.yaml
????????name:?thanos-sidecar
????????image:?thanosio/thanos:v0.25.0
????????env:
????????-?name:?POD_NAME
??????????valueFrom:
????????????fieldRef:
??????????????fieldPath:?metadata.name
????????ports:
????????-?name:?http-sidecar
??????????containerPort:?10902
????????-?name:?grpc
??????????containerPort:?10901
????????livenessProbe:
????????????httpGet:
??????????????port:?10902
??????????????path:?/-/healthy
????????readinessProbe:
??????????httpGet:
????????????port:?10902
????????????path:?/-/ready
????????volumeMounts:
????????-?mountPath:?/data
??????????name:?storage-volume
????????-?name:?thanos-objectstorage
??????????subPath:?objectstorage.yaml
??????????mountPath:?/etc/objectstorage.yaml
新增掛載秘鑰
??????-?name:?thanos-objectstorage
????????secret:
??????????secretName:?thanos-objectstorage
重啟 Prometheus
滾動升級會遇到如下錯(cuò)誤,因?yàn)樯弦粋€(gè) Prometheus Pod 沒有釋放文件目錄導(dǎo)致。
ts=2022-03-21T04:06:39.267Z?caller=main.go:932?level=error?err="opening?storage?failed:?lock?DB?directory:?resource?temporarily?unavailable"
因此需要先將副本數(shù)設(shè)置為 0,在將其設(shè)置為 1,重啟 Prometheus。
kubectl?-n?monitor?scale?deploy?prometheus-server?--replicas=0
kubectl?-n?monitor?scale?deploy?prometheus-server?--replicas=1
5.5 在 Prometheus Sidecar 添加 Grpc 遠(yuǎn)程訪問端口
編輯 Prometheus Service 配置
kubectl?-n?monitor?edit?svc?prometheus-server
新增一個(gè) Service 端口暴露 Grpc 服務(wù)給 Thanos Store Gateway
??ports:
??-?name:?sidecar-grpc
????nodePort:?30901
????port:?10901
????protocol:?TCP
????targetPort:?10901
??type:?NodePort
5.6 在 Thanos Query 添加 Store Grpc 地址
最后還需要在 Thanos Store Gateway 中添加上面 Prometheus Sidecar 的 Grpc 地址。
編輯 Thanos Query
kubectl?-n?thanos?edit?deploy?thanos-query
在啟動參數(shù)中添加 --store=0.0.0.0:30901
??????-?args:
????????-?query
????????-?--log.level=debug
????????-?--query.auto-downsampling
????????-?--grpc-address=0.0.0.0:10901
????????-?--http-address=0.0.0.0:9090
????????-?--query.partial-response
????????-?--query.replica-label=prometheus_replica
????????-?--query.replica-label=rule_replica
????????-?--store=0.0.0.0:30901
????????image:?thanosio/thanos:v0.25.0
這里的 0.0.0.0:30901 需要替換為上面 Prometheus Sidecar 暴露的 Grpc 訪問入口。這樣,Thanos Query 提供查詢能力時(shí),短期數(shù)據(jù)就會調(diào)用 Grpc 查詢,而不是查詢對象存儲中的數(shù)據(jù)。
此時(shí),在上面提到 Thanos Query 頁面以及可以看到新增的 0.0.0.0:30901 這個(gè) Endpoint 記錄,狀態(tài)應(yīng)該是 Up。
5.7 在 Minio 中查看同步的數(shù)據(jù)

一共添加了 6 個(gè)集群,每個(gè)集群大約 40 個(gè) Pod,半天時(shí)間大約用了 2.1 GB 存儲、303 個(gè)對象。
6. Grafana 配置
6.1 添加數(shù)據(jù)源
在 Grafana 添加 Thanos Query 數(shù)據(jù)源的方式和添加 Prometheus 一樣。如下圖:

6.2 修改 Grafana 面板適配 cluster 標(biāo)簽過濾
這里在基于 Kubernetes 集群查看的面板,稍微進(jìn)行修改。
添加 cluster 過濾的變量
在上面,我在每一個(gè) Prometheus 中都添加了一個(gè)全局的 external_labels,通過 cluster 字段來區(qū)分不同的集群。

如上圖,在面板中添加一個(gè) Cluster 變量,使用指標(biāo)中的 cluster 標(biāo)簽進(jìn)行過濾。
編輯每個(gè)視圖的過濾查詢條件

如上圖,需要在每個(gè)視圖的表達(dá)式中增加一個(gè)額外的過濾條件,cluster=~"^$Cluster$"}。當(dāng)然,也可以將面板導(dǎo)出,在編輯器中批量修改之后再導(dǎo)入 Grafana。
6.3 查看 Thanos 和 Prometheus 數(shù)據(jù)源
使用 Thanos 數(shù)據(jù)源

使用 Prometheus 數(shù)據(jù)源

對比兩個(gè)面板的數(shù)據(jù),可以發(fā)現(xiàn)他們展示的指標(biāo)一致。因此,我們可以使用一個(gè) Thanos 數(shù)據(jù)源替代多個(gè) Prometheus 數(shù)據(jù)源分散管理的場景。
這里數(shù)據(jù)的時(shí)間尺度沒有達(dá)到 Thanos Compact 組件的參數(shù)設(shè)置,因此沒有體現(xiàn)出降采樣的效果。
7. 總結(jié)
本篇主要是闡述了監(jiān)控?cái)?shù)據(jù)層管理的一些想法。
首先是數(shù)據(jù)要分層,短期數(shù)據(jù)直接存儲在就近的 Prometheus,長期數(shù)據(jù)存儲在 Thanos 的對象存儲中。短期數(shù)據(jù)提供給告警系統(tǒng)的高頻查詢,長期數(shù)據(jù)提供給人用于分析。
選擇 Thanos 的主要原因是其降采樣。Thanos compact 組件提供了 5 分鐘、1 小時(shí)的降采樣,以 Prometheus 每 15s 采樣頻率計(jì)算,壓縮將達(dá)到 20 倍、240 倍,能夠大大緩解長周期查詢壓力。采用 Sidecar 模式時(shí),短期的數(shù)據(jù)會通過 Grpc 調(diào)用 Prometheus 的 API 查詢。
最后當(dāng)然是將本地用的 6 個(gè)集群都接入了 Thanos。只有親自嘗試過之后,才會真切地體會到其中的一些細(xì)節(jié)和處理邏輯。雖然架構(gòu)圖、文檔、博客看了不少,但是都不如自己親自嘗試一次。
8. 參考
https://thanos.io/tip/thanos/quick-tutorial.md/ https://artifacthub.io/packages/helm/bitnami/thanos https://github.com/shaowenchen/demo https://imroc.cc/post/202004/build-cloud-native-large-scale-distributed-monitoring-system-3/
參考資料
Jenkins 中的構(gòu)建產(chǎn)物與緩存: https://www.chenshaowen.com/blog/artifacts-and-cache-in-jenkins.html#11-部署-minio
