Prometheus 服務(wù)的自動(dòng)發(fā)現(xiàn)使用
前面我們了解了 Prometheus 中 Relabeling 重新標(biāo)記的使用,本文我們將學(xué)習(xí) Prometheus 中是如何使用服務(wù)發(fā)現(xiàn)來(lái)查找和抓取目標(biāo)的。我們知道在 Prometheus 配置文件中可以通過(guò)一個(gè) static_configs 來(lái)配置靜態(tài)的抓取任務(wù),但是在云環(huán)境下,特別是容器環(huán)境下,抓取目標(biāo)地址是經(jīng)常變動(dòng)的,所以用靜態(tài)的方式就不能滿足這些場(chǎng)景了。所以我們需要監(jiān)控系統(tǒng)能夠動(dòng)態(tài)感知這個(gè)變化,不可能每次變動(dòng)都去手動(dòng)重新配置的,為了應(yīng)對(duì)復(fù)雜的動(dòng)態(tài)環(huán)境,Prometheus 也提供了與基礎(chǔ)設(shè)施中的服務(wù)發(fā)現(xiàn)集成的功能。

Prometheus 已經(jīng)支持多種內(nèi)置的服務(wù)發(fā)現(xiàn)機(jī)制:
發(fā)現(xiàn)云服務(wù)商的 VM 虛擬機(jī) Kubernetes 上的自動(dòng)發(fā)現(xiàn) 通用的服務(wù)查找,例如 DNS、Consul、Zookeeper 或自定義發(fā)現(xiàn)機(jī)制
我們都可以通過(guò) Prometheus 配置文件中的 scrape_config 部分進(jìn)行配置,Prometheus 會(huì)不斷更新動(dòng)態(tài)的抓取目標(biāo)列表,自動(dòng)停止抓取舊的實(shí)例,開(kāi)始抓取新的實(shí)例,Prometheus 特別適合運(yùn)行于 Kubernetes 集群下面,可以自動(dòng)發(fā)現(xiàn)監(jiān)控目標(biāo)。
此外大部分服務(wù)發(fā)現(xiàn)機(jī)制還會(huì)提供目標(biāo)的一些元數(shù)據(jù),通常都是帶有 __ 的前綴, 比如標(biāo)簽、注解、服務(wù)名等等,可以在 relabeling 階段使用這些元數(shù)據(jù)來(lái)過(guò)濾修改目標(biāo),這些元信息標(biāo)簽在重新標(biāo)記階段后被刪除。
基于 Consul 的服務(wù)發(fā)現(xiàn)
Consul 是由 HashiCorp 開(kāi)發(fā)的一個(gè)支持多數(shù)據(jù)中心的分布式服務(wù)發(fā)現(xiàn)和鍵值對(duì)存儲(chǔ)服務(wù)的開(kāi)源軟件,是一個(gè)通用的服務(wù)發(fā)現(xiàn)和注冊(cè)中心工具,被大量應(yīng)用于基于微服務(wù)的軟件架構(gòu)當(dāng)中。
接下來(lái)我們就來(lái)嘗試使用 Prometheus 基于 Consul 的服務(wù)發(fā)現(xiàn)來(lái)監(jiān)控前面的 3 個(gè) demo 服務(wù):
192.168.31.46:10000
192.168.31.46:10001
192.168.31.46:10002
我們將 demo 服務(wù)注冊(cè)到 Consul,然后配置 Prometheus 從 Consul 中發(fā)現(xiàn)演示服務(wù)實(shí)例,并使用 Relabeling 操作來(lái)過(guò)濾調(diào)整目標(biāo)標(biāo)簽。關(guān)于 Consul 本身的使用可以查看官方文檔 https://learn.hashicorp.com/consul 了解更多。

安裝配置 Consul
在頁(yè)面 https://www.consul.io/downloads 下載符合自己系統(tǒng)的安裝文件,比如我們這里是 Linux 系統(tǒng),使用下面命令下載安裝即可:
????wget?https://releases.hashicorp.com/consul/1.10.2/consul_1.10.2_linux_amd64.zip
????unzip?consul_1.10.2_linux_amd64.zip
#?將?consul?二進(jìn)制移動(dòng)到?PATH?路徑下去
????mv?consul?/usr/local/bin
????consul?version
Consul?v1.10.2
Revision?3cb6eeedb
Protocol?2?spoken?by?default,?understands?2?to?3?(agent?will?automatically?use?protocol?>2?when?speaking?to?compatible?agents)
當(dāng)執(zhí)行 consul 命令后正常有命令提示,證明已經(jīng)安裝完成。接著創(chuàng)建一個(gè)用于注冊(cè) demo 服務(wù)的 Consul 配置文件 demo-service.json:
{
??"services":?[
????{
??????"id":?"demo1",
??????"name":?"demo",
??????"address":?"192.168.31.46",
??????"port":?10000,
??????"meta":?{
????????"env":?"production"
??????},
??????"checks":?[
????????{
??????????"http":?"http://192.168.31.46:10000/api/foo",
??????????"interval":?"1s"
????????}
??????]
????},
????{
??????"id":?"demo2",
??????"name":?"demo",
??????"address":?"192.168.31.46",
??????"port":?10001,
??????"meta":?{
????????"env":?"production"
??????},
??????"checks":?[
????????{
??????????"http":?"http://192.168.31.46:10001/api/foo",
??????????"interval":?"1s"
????????}
??????]
????},
????{
??????"id":?"demo3",
??????"name":?"demo",
??????"address":?"192.168.31.46",
??????"port":?10002,
??????"meta":?{
????????"env":?"staging"
??????},
??????"checks":?[
????????{
??????????"http":?"http://192.168.31.46:10002/api/foo",
??????????"interval":?"1s"
????????}
??????]
????}
??]
}
當(dāng)然一般情況下我們也是在 Consul 中進(jìn)行動(dòng)態(tài)注冊(cè)服務(wù),但是這里我們只是簡(jiǎn)單演示 Prometheus 基于 Consul 的服務(wù)發(fā)現(xiàn),這里只使用 Consul 配置文件靜態(tài)注冊(cè)服務(wù)即可。Consul 允許使用 JSON 中的 meta屬性將 key-value 元數(shù)據(jù)與每個(gè)注冊(cè)的服務(wù)實(shí)例相關(guān)聯(lián),比如這里我們配置的 env 屬性和部署環(huán)境 production 或 staging 進(jìn)行關(guān)聯(lián),后面我們可以通過(guò)使用 Prometheus 里面的 Relabeling 操作提取該字段并將其映射到每個(gè)抓取實(shí)例的標(biāo)簽中去。
為了查看更多的日志信息,我們可以在 dev 模式下運(yùn)行 Consul,如下所示:
????consul?agent?-dev?-config-file=demo-service.json?-client?0.0.0.0
==>?Starting?Consul?agent...
???????????Version:?'1.10.2'
???????????Node?ID:?'a4a9418c-7f7d-a2da-c81e-94d3d37601aa'
?????????Node?name:?'node2'
????????Datacenter:?'dc1'?(Segment:?'')
????????????Server:?true?(Bootstrap:?false)
???????Client?Addr:?[0.0.0.0]?(HTTP:?8500,?HTTPS:?-1,?gRPC:?8502,?DNS:?8600)
??????Cluster?Addr:?127.0.0.1?(LAN:?8301,?WAN:?8302)
???????????Encrypt:?Gossip:?false,?TLS-Outgoing:?false,?TLS-Incoming:?false,?Auto-Encrypt-TLS:?false
==>?Log?data?will?now?stream?in?as?it?occurs:
......
這里我們?cè)趩?dòng)命令后面使用 -client 參數(shù)指定了客戶端綁定的 IP 地址,默認(rèn)為 127.0.0.1。除了我們注冊(cè)的 3 個(gè) demo 服務(wù)之外,Consul agent 還會(huì)將自己注冊(cè)為一個(gè)名為 consul 的服務(wù),我們可以在瀏覽器中訪問(wèn) http:// 查看注冊(cè)的服務(wù)。

在 Consul UI 頁(yè)面中可以看到有 consul 和 demo 兩個(gè) Service 服務(wù)。
配置 Consul 自動(dòng)發(fā)現(xiàn)
上面我們通過(guò) Consul 注冊(cè)了 3 個(gè) demo 服務(wù),接下來(lái)我們將配置 Prometheus 通過(guò) Consul 來(lái)自動(dòng)發(fā)現(xiàn) demo 服務(wù)。
在 Prometheus 的配置文件 prometheus.yml 文件中的 scrape_configs 部分添加如下所示的抓取配置:
scrape_configs:
??-?job_name:?"consul-sd-demo"
????consul_sd_configs:
??????-?server:?"localhost:8500"
????relabel_configs:
??????-?action:?keep
????????source_labels:?[__meta_consul_service,?__meta_consul_health]
????????regex:?demo;passing
??????-?action:?labelmap
????????regex:?__meta_consul_service_metadata_(.*)
????????replacement:?consul_$1
這里我們添加了一個(gè)名為 consul-sd-demo 的抓取任務(wù),通過(guò) consul_sd_configs 配置用于自動(dòng)發(fā)現(xiàn)的 Consul 服務(wù)地址,然后使用 relabel_configs 進(jìn)行了重新標(biāo)記配置,首先只保留服務(wù)名稱(chēng)為 demo,且健康狀態(tài)為 passing 的,否則也會(huì)抓取 Consul Agent 本身,而它自身是不提供 metrics 接口數(shù)據(jù)的,另外還使用 labelmap 進(jìn)行了標(biāo)簽映射,將所有 Consul 元標(biāo)簽映射到 Prometheus 中以 consul_ 為前綴的標(biāo)簽中。
配置完成后重新啟動(dòng) Prometheus,然后重新查看 Prometheus 頁(yè)面上的 targets 頁(yè)面,驗(yàn)證上面的配置是否存在:

正常情況下是可以看到會(huì)有一個(gè) consul-sd-demo 的任務(wù),下面有 3 個(gè)自動(dòng)發(fā)現(xiàn)的抓取目標(biāo)。
我們將鼠標(biāo)懸停在 Labels 標(biāo)簽區(qū)域就可以看到目標(biāo)任務(wù)在重新標(biāo)記 Relabeling 之前的原始標(biāo)簽。比如我們將查看第一個(gè) demo 實(shí)例在 Relabel 之前包含如下所示的這些原始標(biāo)簽:

通過(guò)查看網(wǎng)絡(luò)請(qǐng)求接口 http:// 也可以獲取對(duì)應(yīng)的原始標(biāo)簽數(shù)據(jù):
{
??"discoveredLabels":?{
????"__address__":?"192.168.31.46:10000",
????"__meta_consul_address":?"127.0.0.1",
????"__meta_consul_dc":?"dc1",
????"__meta_consul_health":?"passing",
????"__meta_consul_node":?"node2",
????"__meta_consul_service":?"demo",
????"__meta_consul_service_address":?"192.168.31.46",
????"__meta_consul_service_id":?"demo1",
????"__meta_consul_service_metadata_env":?"production",
????"__meta_consul_service_port":?"10000",
????"__meta_consul_tagged_address_lan":?"127.0.0.1",
????"__meta_consul_tagged_address_lan_ipv4":?"127.0.0.1",
????"__meta_consul_tagged_address_wan":?"127.0.0.1",
????"__meta_consul_tagged_address_wan_ipv4":?"127.0.0.1",
????"__meta_consul_tags":?",,",
????"__metrics_path__":?"/metrics",
????"__scheme__":?"http",
????"job":?"consul-sd-demo"
??},
??"labels":?{
????"consul_env":?"production",
????"instance":?"192.168.31.46:10000",
????"job":?"consul-sd-demo"
??},
??"scrapePool":?"consul-sd-demo",
??"scrapeUrl":?"http://192.168.31.46:10000/metrics",
??"globalUrl":?"http://192.168.31.46:10000/metrics",
??"lastError":?"",
??"lastScrape":?"2021-09-28T11:56:01.919216851+08:00",
??"lastScrapeDuration":?0.013357276,
??"health":?"up"
}
我們?cè)?relabel_configs 中首先配置了一個(gè) keep 操作,只保留原始標(biāo)簽 __meta_consul_service 值為 demo,且 __meta_consul_health 為 passing 狀態(tài)的抓取任務(wù)。然后使用 labelmap 進(jìn)行標(biāo)簽映射,這里我們將匹配 __meta_consul_service_metadata_(.*) 所有標(biāo)簽,這里只有 __meta_consul_service_metadata_env 這個(gè)原始標(biāo)簽符合正則表達(dá)式,其中的 env 就是匹配的捕獲組,在 replacement 中用 $1 代替,替換成標(biāo)簽 consul_$1,也就是 consul_env 這個(gè)標(biāo)簽了,所以 Relabeling 過(guò)后就只剩下下面的幾個(gè)目標(biāo)標(biāo)簽了:
instance:?"192.168.31.46:10000"
job:?"consul-sd-demo"
consul_env:?"production"
其中的 instance 標(biāo)簽是在重新標(biāo)記之后,自動(dòng)從 __address__ 轉(zhuǎn)變而來(lái)的。由于沒(méi)有重新修改 __metrics_path__ 和 __scheme__ 標(biāo)簽,所以默認(rèn)的抓取目標(biāo)就是通過(guò) HTTP 端點(diǎn) /metrics 進(jìn)行抓取。
現(xiàn)在如果我們將 demo1 這個(gè)服務(wù)殺掉,則在 Consul 中注冊(cè)的服務(wù)就會(huì)出現(xiàn)一個(gè)不健康的實(shí)例:

當(dāng)然此時(shí) Prometheus 中就只剩下兩個(gè)正常 demo 服務(wù)的實(shí)例了:

當(dāng)服務(wù)正常后就又可以自動(dòng)發(fā)現(xiàn)對(duì)應(yīng)的服務(wù)了。這樣我們就完成了 Prometheus 基于 Consul 的一個(gè)簡(jiǎn)單的自動(dòng)發(fā)現(xiàn)配置。
基于文件的服務(wù)發(fā)現(xiàn)
除了基于 Consul 的服務(wù)發(fā)現(xiàn)之外,Prometheus 也允許我們進(jìn)行自定義的發(fā)現(xiàn)集成,可以通過(guò) watch 一組本地文件來(lái)獲取抓取目標(biāo)以及標(biāo)簽信息,也就是我們常說(shuō)的基于文件的服務(wù)發(fā)現(xiàn)方式。

基于文件的服務(wù)發(fā)現(xiàn)提供了一種更通用的方式來(lái)配置靜態(tài)目標(biāo),并作為一個(gè)接口插入自定義服務(wù)發(fā)現(xiàn)機(jī)制。
它讀取一組包含零個(gè)或多個(gè) 列表的文件,對(duì)所有定義的文件的變更通過(guò)磁盤(pán)監(jiān)視被檢測(cè)到并立即應(yīng)用,文件可以以 YAML 或 JSON 格式提供。文件必須包含一個(gè)靜態(tài)配置的列表:
JSON?json?[?{?"targets":?[?"",?...?],?"labels":?{?"":?"",?...?}?},?...?]
YAML?yaml?-?targets:?[?-?''?]?labels:?[?:??...?]
文件內(nèi)容也會(huì)在指定的刷新間隔時(shí)間內(nèi)定期重新讀取。
#?Patterns?for?files?from?which?target?groups?are?extracted.
files:
??[?-? ?...?]
#?Refresh?interval?to?re-read?the?files.
[?refresh_interval:? ?|?default?=?5m?]
其中 可以是一個(gè)以 .json、.yml 或 .yaml 結(jié)尾的路徑,最后一個(gè)路徑段可以包含一個(gè)匹配任何字符序列的 *,例如:my/path/tg_*.json。
創(chuàng)建文件
接下來(lái)我們來(lái)創(chuàng)建一個(gè)用于服務(wù)發(fā)現(xiàn)的目標(biāo)文件,在與 prometheus.yml 文件相同目錄下面創(chuàng)建一個(gè)名為 targets.yml 的文件,內(nèi)容如下所示:
-?targets:
????-?"192.168.31.46:10000"
????-?"192.168.31.46:10001"
??labels:
????env:?production
-?targets:
????-?"192.168.31.46:10002"
??labels:
????env:?staging
該文件中我們列舉了 3 個(gè) demo 服務(wù)實(shí)例,給前兩個(gè)實(shí)例添加上了 env=production 的標(biāo)簽,后面一個(gè)加上了 env=staging 的標(biāo)簽,當(dāng)然該文件也可以使用 JSON 格式進(jìn)行配置:
[
??{
????"targets":?[?"" ,?...?],
????"labels":?{
??????"" :?"" ,?...
????}
??},
??...
]
如果是 YAML 文件則格式為:
-?targets:
??[?-?'' ?]
??labels:
????[?: ? ?...?]
配置文件服務(wù)發(fā)現(xiàn)
用于發(fā)現(xiàn)的目標(biāo)文件創(chuàng)建完成后,要讓 Prometheus 能夠從上面的 targets.yml 文件中自動(dòng)讀取抓取目標(biāo),需要在 prometheus.yml 配置文件中的 scrape_configs 部分添加如下所示的抓取配置:
-?job_name:?"file-sd-demo"
??file_sd_configs:
????-?files:
????????-?"targets.yml"
重新 reload 或者重啟下 Prometheus 讓其重新讀取配置文件信息,然后同樣前往 Prometheus UI 的 targets 頁(yè)面下面查看是否有上面定義的抓取目標(biāo)。

然后我們可以嘗試改變 targets.yml 的內(nèi)容,比如為第三個(gè)實(shí)例增加一個(gè) role: sd 的標(biāo)簽,不用重新加載 Prometheus 配置,Prometheus 將 watch 該文件,并自動(dòng)接收任何變化。
注意:當(dāng)在生產(chǎn)環(huán)境 Prometheus 服務(wù)器中改變
file_sd目標(biāo)文件時(shí),需要確保改變是原子的,以避免重新加載出現(xiàn)錯(cuò)誤,最好的方法是在一個(gè)單獨(dú)的位置創(chuàng)建更新的文件,然后將其重命名為目標(biāo)文件名(使用mv命令或rename()系統(tǒng)調(diào)用)。

這樣我們就完成了基于文件的通用服務(wù)發(fā)現(xiàn)機(jī)制,可以讓我們動(dòng)態(tài)地改變 Prometheus 的監(jiān)控目標(biāo),而不需要重新啟動(dòng)或重新加載 Prometheus 服務(wù)。當(dāng)然除了基于 Consul 和文件的服務(wù)發(fā)現(xiàn)之外,更多的時(shí)候我們會(huì)在 Kubernetes 環(huán)境下面使用 Prometheus,由于這部分內(nèi)容比較獨(dú)立,后續(xù)我們?cè)龠M(jìn)行單獨(dú)講解(其實(shí)前面已經(jīng)詳細(xì)介紹過(guò)了)。
