本章節講解服務發現與Relabelling的機制與范例。
通過服務發現的方式,我們可以在不重啟Prometheus服務的情況下動態的發現需要監控的Target實例信息。
如上圖所示,對于線上環境我們可能會劃分為:dev, stage, prod不同的集群。每一個集群運行多個主機節點,每個服務器節點上運行一個Node Exporter實例。Node Exporter實例會自動注冊到Consul中,而Prometheus則根據Consul返回的Node Exporter實例信息動態的維護Target列表,從而向這些Target輪詢監控數據。
然而,如果我們可能還需要:
- 按照不同的環境dev, stage, prod聚合監控數據?
- 對于研發團隊而言,我可能只關心dev環境的監控數據,如何處理?
- 如果為每一個團隊單獨搭建一個Prometheus Server。那么如何讓不同團隊的Prometheus Server采集不同的環境監控數據?
面對以上這些場景下的需求時,我們實際上是希望Prometheus Server能夠按照某些規則(比如標簽)從服務發現注冊中心返回的Target實例中有選擇性的采集某些Exporter實例的監控數據。
接下來,我們實驗如何通過Prometheus強大的Relabel機制來實現以上這些具體的目標。
Prometheus的Relabeling機制
在Prometheus所有的Target實例中,都包含一些默認的Metadata標簽信息。可以通過Prometheus UI的Targets頁面中查看這些實例的Metadata標簽的內容:
默認情況下,當Prometheus加載Target實例完成后,這些Target時候都會包含一些默認的標簽:
__address__:當前Target實例的訪問地址<host>:<port>
__scheme__:采集目標服務訪問地址的HTTP Scheme,HTTP或者HTTPS
__metrics_path__:采集目標服務訪問地址的訪問路徑
__param_<name>:采集任務目標服務的中包含的請求參數
上面這些標簽將會告訴Prometheus如何從該Target實例中獲取監控數據。除了這些默認的標簽以外,我們還可以為Target添加自定義的標簽,例如,在“基于文件的服務發現”小節中的示例中,我們通過JSON配置文件,為Target實例添加了自定義標簽env,如下所示該標簽最終也會保存到從該實例采集的樣本數據中:
node_cpu{cpu="cpu0",env="prod",instance="localhost:9100",job="node",mode="idle"}
一般來說,Target以__作為前置的標簽是在系統內部使用的,因此這些標簽不會被寫入到樣本數據中。不過這里有一些例外,例如,我們會發現所有通過Prometheus采集的樣本數據中都會包含一個名為instance的標簽,該標簽的內容對應到Target實例的address。 這里實際上是發生了一次標簽的重寫處理。
這種發生在采集樣本數據之前,對Target實例的標簽進行重寫的機制在Prometheus被稱為Relabeling。
Prometheus允許用戶在采集任務設置中通過relabel_configs來添加自定義的Relabeling過程。
使用replace/labelmap重寫標簽
Relabeling最基本的應用場景就是基于Target實例中包含的metadata標簽,動態的添加或者覆蓋標簽。例如,通過Consul動態發現的服務實例還會包含以下Metadata標簽信息:
__meta_consul_address:consul地址
__meta_consul_dc:consul服務所在的數據中心
__meta_consulmetadata:服務的metadata
__meta_consul_node:consul服務node節點的信息
__meta_consul_service_address:服務訪問地址
__meta_consul_service_id:服務ID
__meta_consul_service_port:服務端口
__meta_consul_service:服務名稱
__meta_consul_tags:服務包含的標簽信息
在默認情況下,從Node Exporter實例采集上來的樣本數據如下所示:
node_cpu{cpu="cpu0",instance="localhost:9100",job="node",mode="idle"} 93970.8203125
我們希望能有一個額外的標簽dc可以表示該樣本所屬的數據中心:
node_cpu{cpu="cpu0",instance="localhost:9100",job="node",mode="idle", dc="dc1"} 93970.8203125
在每一個采集任務的配置中可以添加多個relabel_config配置,一個最簡單的relabel配置如下:
scrape_configs:
- job_name: node_exporter
consul_sd_configs:
- server: localhost:8500
services:
- node_exporter
relabel_configs:
- source_labels: ["__meta_consul_dc"]
target_label: "dc"
該采集任務通過Consul動態發現Node Exporter實例信息作為監控采集目標。在上一小節中,我們知道通過Consul動態發現的監控Target都會包含一些額外的Metadata標簽,比如標簽__meta_consul_dc表明了當前實例所在的Consul數據中心,因此我們希望從這些實例中采集到的監控樣本中也可以包含這樣一個標簽,例如:
node_cpu{cpu="cpu0",dc="dc1",instance="172.21.0.6:9100",job="consul_sd",mode="guest"}
這樣可以方便的根據dc標簽的值,根據不同的數據中心聚合分析各自的數據。
在這個例子中,通過從Target實例中獲取__meta_consul_dc的值,并且重寫所有從該實例獲取的樣本中。
完整的relabel_config配置如下所示:
# The source labels select values from existing labels. Their content is concatenated
# using the configured separator and matched against the configured regular expression
# for the replace, keep, and drop actions.
[ source_labels: '[' <labelname> [, ...] ']' ]
# Separator placed between concatenated source label values.
[ separator: <string> | default = ; ]
# Label to which the resulting value is written in a replace action.
# It is mandatory for replace actions. Regex capture groups are available.
[ target_label: <labelname> ]
# Regular expression against which the extracted value is matched.
[ regex: <regex> | default = (.*) ]
# Modulus to take of the hash of the source label values.
[ modulus: <uint64> ]
# Replacement value against which a regex replace is performed if the
# regular expression matches. Regex capture groups are available.
[ replacement: <string> | default = $1 ]
# Action to perform based on regex matching.
[ action: <relabel_action> | default = replace ]
其中action定義了當前relabel_config對Metadata標簽的處理方式,默認的action行為為replace。 replace行為會根據regex的配置匹配source_labels標簽的值(多個source_label的值會按照separator進行拼接),并且將匹配到的值寫入到target_label當中,如果有多個匹配組,則可以使用{2}確定寫入的內容。如果沒匹配到任何內容則不對target_label進行重新。
repalce操作允許用戶根據Target的Metadata標簽重寫或者寫入新的標簽鍵值對,在多環境的場景下,可以幫助用戶添加與環境相關的特征維度,從而可以更好的對數據進行聚合。
除了使用replace以外,還可以定義action的配置為labelmap。與replace不同的是,labelmap會根據regex的定義去匹配Target實例所有標簽的名稱,并且以匹配到的內容為新的標簽名稱,其值作為新標簽的值。
例如,在監控Kubernetes下所有的主機節點時,為將這些節點上定義的標簽寫入到樣本中時,可以使用如下relabel_config配置:
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
而使用labelkeep或者labeldrop則可以對Target標簽進行過濾,僅保留符合過濾條件的標簽,例如:
relabel_configs:
- regex: label_should_drop_(.+)
action: labeldrop
該配置會使用regex匹配當前Target實例的所有標簽,并將符合regex規則的標簽從Target實例中移除。labelkeep正好相反,會移除那些不匹配regex定義的所有標簽。
使用keep/drop過濾Target實例
在上一部分中我們介紹了Prometheus的Relabeling機制,并且使用了replace/labelmap/labelkeep/labeldrop對標簽進行管理。而本節開頭還提到過第二個問題,使用中心化的服務發現注冊中心時,所有環境的Exporter實例都會注冊到該服務發現注冊中心中。而不同職能(開發、測試、運維)的人員可能只關心其中一部分的監控數據,他們可能各自部署的自己的Prometheus Server用于監控自己關心的指標數據,如果讓這些Prometheus Server采集所有環境中的所有Exporter數據顯然會存在大量的資源浪費。如何讓這些不同的Prometheus Server采集各自關心的內容?答案還是Relabeling,relabel_config的action除了默認的replace以外,還支持keep/drop行為。例如,如果我們只希望采集數據中心dc1中的Node Exporter實例的樣本數據,那么可以使用如下配置:
scrape_configs:
- job_name: node_exporter
consul_sd_configs:
- server: localhost:8500
services:
- node_exporter
relabel_configs:
- source_labels: ["__meta_consul_dc"]
regex: "dc1"
action: keep
當action設置為keep時,Prometheus會丟棄source_labels的值中沒有匹配到regex正則表達式內容的Target實例,而當action設置為drop時,則會丟棄那些source_labels的值匹配到regex正則表達式內容的Target實例。可以簡單理解為keep用于選擇,而drop用于排除。
使用hashmod計算source_labels的Hash值
當relabel_config設置為hashmod時,Prometheus會根據modulus的值作為系數,計算source_labels值的hash值。例如:
scrape_configs
- job_name: 'file_ds'
relabel_configs:
- source_labels: [__address__]
modulus: 4
target_label: tmp_hash
action: hashmod
file_sd_configs:
- files:
- targets.json
根據當前Target實例address的值以4作為系數,這樣每個Target實例都會包含一個新的標簽tmp_hash,并且該值的范圍在1~4之間,查看Target實例的標簽信息,可以看到如下的結果,每一個Target實例都包含了一個新的tmp_hash值:
利用Hashmod的能力在Target實例級別實現對采集任務的功能分區的:
scrape_configs:
- job_name: some_job
relabel_configs:
- source_labels: [__address__]
modulus: 4
target_label: __tmp_hash
action: hashmod
- source_labels: [__tmp_hash]
regex: ^1$
action: keep
這里需要注意的是,如果relabel的操作只是為了產生一個臨時變量,以作為下一個relabel操作的輸入,那么我們可以使用 __tmp
作為標簽名的前綴,通過該前綴定義的標簽就不會寫入到Target或者采集到的樣本的標簽中。