Prometheus 服務(wù)的自動發(fā)現(xiàn)使用
前面我們了解了 Prometheus 中 Relabeling 重新標記的使用,本文我們將學(xué)習 Prometheus 中是如何使用服務(wù)發(fā)現(xiàn)來查找和抓取目標的。我們知道在 Prometheus 配置文件中可以通過一個 static_configs 來配置靜態(tài)的抓取任務(wù),但是在云環(huán)境下,特別是容器環(huán)境下,抓取目標地址是經(jīng)常變動的,所以用靜態(tài)的方式就不能滿足這些場景了。所以我們需要監(jiān)控系統(tǒng)能夠動態(tài)感知這個變化,不可能每次變動都去手動重新配置的,為了應(yīng)對復(fù)雜的動態(tài)環(huán)境,Prometheus 也提供了與基礎(chǔ)設(shè)施中的服務(wù)發(fā)現(xiàn)集成的功能。
Prometheus 已經(jīng)支持多種內(nèi)置的服務(wù)發(fā)現(xiàn)機制:
- 發(fā)現(xiàn)云服務(wù)商的 VM 虛擬機
- Kubernetes 上的自動發(fā)現(xiàn)
- 通用的服務(wù)查找,例如 DNS、Consul、Zookeeper 或自定義發(fā)現(xiàn)機制
我們都可以通過 Prometheus 配置文件中的 scrape_config 部分進行配置,Prometheus 會不斷更新動態(tài)的抓取目標列表,自動停止抓取舊的實例,開始抓取新的實例,Prometheus 特別適合運行于 Kubernetes 集群下面,可以自動發(fā)現(xiàn)監(jiān)控目標。
此外大部分服務(wù)發(fā)現(xiàn)機制還會提供目標的一些元數(shù)據(jù),通常都是帶有 __ 的前綴, 比如標簽、注解、服務(wù)名等等,可以在 relabeling 階段使用這些元數(shù)據(jù)來過濾修改目標,這些元信息標簽在重新標記階段后被刪除。
基于 Consul 的服務(wù)發(fā)現(xiàn)
Consul 是由 HashiCorp 開發(fā)的一個支持多數(shù)據(jù)中心的分布式服務(wù)發(fā)現(xiàn)和鍵值對存儲服務(wù)的開源軟件,是一個通用的服務(wù)發(fā)現(xiàn)和注冊中心工具,被大量應(yīng)用于基于微服務(wù)的軟件架構(gòu)當中。
接下來我們就來嘗試使用 Prometheus 基于 Consul 的服務(wù)發(fā)現(xiàn)來監(jiān)控前面的 3 個 demo 服務(wù):
- 192.168.31.46:10000
- 192.168.31.46:10001
- 192.168.31.46:10002
我們將 demo 服務(wù)注冊到 Consul,然后配置 Prometheus 從 Consul 中發(fā)現(xiàn)演示服務(wù)實例,并使用 Relabeling 操作來過濾調(diào)整目標標簽。關(guān)于 Consul 本身的使用可以查看官方文檔 https://learn.hashicorp.com/consul 了解更多。
安裝配置 Consul
在頁面 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 二進制移動到 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)
當執(zhí)行 consul 命令后正常有命令提示,證明已經(jīng)安裝完成。接著創(chuàng)建一個用于注冊 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"
- }
- ]
- }
- ]
- }
當然一般情況下我們也是在 Consul 中進行動態(tài)注冊服務(wù),但是這里我們只是簡單演示 Prometheus 基于 Consul 的服務(wù)發(fā)現(xiàn),這里只使用 Consul 配置文件靜態(tài)注冊服務(wù)即可。Consul 允許使用 JSON 中的 meta屬性將 key-value 元數(shù)據(jù)與每個注冊的服務(wù)實例相關(guān)聯(lián),比如這里我們配置的 env 屬性和部署環(huán)境 production 或 staging 進行關(guān)聯(lián),后面我們可以通過使用 Prometheus 里面的 Relabeling 操作提取該字段并將其映射到每個抓取實例的標簽中去。
為了查看更多的日志信息,我們可以在 dev 模式下運行 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: '<all>')
- 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:
- ......
這里我們在啟動命令后面使用 -client 參數(shù)指定了客戶端綁定的 IP 地址,默認為 127.0.0.1。除了我們注冊的 3 個 demo 服務(wù)之外,Consul agent 還會將自己注冊為一個名為 consul 的服務(wù),我們可以在瀏覽器中訪問 http://
在 Consul UI 頁面中可以看到有 consul 和 demo 兩個 Service 服務(wù)。
配置 Consul 自動發(fā)現(xiàn)
上面我們通過 Consul 注冊了 3 個 demo 服務(wù),接下來我們將配置 Prometheus 通過 Consul 來自動發(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
這里我們添加了一個名為 consul-sd-demo 的抓取任務(wù),通過 consul_sd_configs 配置用于自動發(fā)現(xiàn)的 Consul 服務(wù)地址,然后使用 relabel_configs 進行了重新標記配置,首先只保留服務(wù)名稱為 demo,且健康狀態(tài)為 passing 的,否則也會抓取 Consul Agent 本身,而它自身是不提供 metrics 接口數(shù)據(jù)的,另外還使用 labelmap 進行了標簽映射,將所有 Consul 元標簽映射到 Prometheus 中以 consul_ 為前綴的標簽中。
配置完成后重新啟動 Prometheus,然后重新查看 Prometheus 頁面上的 targets 頁面,驗證上面的配置是否存在:
正常情況下是可以看到會有一個 consul-sd-demo 的任務(wù),下面有 3 個自動發(fā)現(xiàn)的抓取目標。
我們將鼠標懸停在 Labels 標簽區(qū)域就可以看到目標任務(wù)在重新標記 Relabeling 之前的原始標簽。比如我們將查看第一個 demo 實例在 Relabel 之前包含如下所示的這些原始標簽:
通過查看網(wǎng)絡(luò)請求接口 http://<promtheus addr>/api/v1/targets?state=active 也可以獲取對應(yīng)的原始標簽數(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"
- }
我們在 relabel_configs 中首先配置了一個 keep 操作,只保留原始標簽 __meta_consul_service 值為 demo,且 __meta_consul_health 為 passing 狀態(tài)的抓取任務(wù)。然后使用 labelmap 進行標簽映射,這里我們將匹配 __meta_consul_service_metadata_(.*) 所有標簽,這里只有 __meta_consul_service_metadata_env 這個原始標簽符合正則表達式,其中的 env 就是匹配的捕獲組,在 replacement 中用 $1 代替,替換成標簽 consul_$1,也就是 consul_env 這個標簽了,所以 Relabeling 過后就只剩下下面的幾個目標標簽了:
- instance: "192.168.31.46:10000"
- job: "consul-sd-demo"
- consul_env: "production"
其中的 instance 標簽是在重新標記之后,自動從 __address__ 轉(zhuǎn)變而來的。由于沒有重新修改 __metrics_path__ 和 __scheme__ 標簽,所以默認的抓取目標就是通過 HTTP 端點 /metrics 進行抓取。
現(xiàn)在如果我們將 demo1 這個服務(wù)殺掉,則在 Consul 中注冊的服務(wù)就會出現(xiàn)一個不健康的實例:
當然此時 Prometheus 中就只剩下兩個正常 demo 服務(wù)的實例了:
當服務(wù)正常后就又可以自動發(fā)現(xiàn)對應(yīng)的服務(wù)了。這樣我們就完成了 Prometheus 基于 Consul 的一個簡單的自動發(fā)現(xiàn)配置。
基于文件的服務(wù)發(fā)現(xiàn)
除了基于 Consul 的服務(wù)發(fā)現(xiàn)之外,Prometheus 也允許我們進行自定義的發(fā)現(xiàn)集成,可以通過 watch 一組本地文件來獲取抓取目標以及標簽信息,也就是我們常說的基于文件的服務(wù)發(fā)現(xiàn)方式。
基于文件的服務(wù)發(fā)現(xiàn)提供了一種更通用的方式來配置靜態(tài)目標,并作為一個接口插入自定義服務(wù)發(fā)現(xiàn)機制。
它讀取一組包含零個或多個
- JSON json [ { "targets": [ "<host>", ... ], "labels": { "<labelname>": "<labelvalue>", ... } }, ... ]
- YAML yaml - targets: [ - '<host>' ] labels: [ <labelname>: <labelvalue> ... ]
文件內(nèi)容也會在指定的刷新間隔時間內(nèi)定期重新讀取。
- # Patterns for files from which target groups are extracted.
- files:
- [ - <filename_pattern> ... ]
- # Refresh interval to re-read the files.
- [ refresh_interval: <duration> | default = 5m ]
其中 <filename*pattern> 可以是一個以 .json、.yml 或 .yaml 結(jié)尾的路徑,最后一個路徑段可以包含一個匹配任何字符序列的 *,例如:my/path/tg_*.json。
創(chuàng)建文件
接下來我們來創(chuàng)建一個用于服務(wù)發(fā)現(xiàn)的目標文件,在與 prometheus.yml 文件相同目錄下面創(chuàng)建一個名為 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 個 demo 服務(wù)實例,給前兩個實例添加上了 env=production 的標簽,后面一個加上了 env=staging 的標簽,當然該文件也可以使用 JSON 格式進行配置:
- [
- {
- "targets": [ "<host>", ... ],
- "labels": {
- "<labelname>": "<labelvalue>", ...
- }
- },
- ...
- ]
如果是 YAML 文件則格式為:
- - targets:
- [ - '<host>' ]
- labels:
- [ <labelname>: <labelvalue> ... ]
配置文件服務(wù)發(fā)現(xiàn)
用于發(fā)現(xiàn)的目標文件創(chuàng)建完成后,要讓 Prometheus 能夠從上面的 targets.yml 文件中自動讀取抓取目標,需要在 prometheus.yml 配置文件中的 scrape_configs 部分添加如下所示的抓取配置:
- - job_name: "file-sd-demo"
- file_sd_configs:
- - files:
- - "targets.yml"
重新 reload 或者重啟下 Prometheus 讓其重新讀取配置文件信息,然后同樣前往 Prometheus UI 的 targets 頁面下面查看是否有上面定義的抓取目標。
然后我們可以嘗試改變 targets.yml 的內(nèi)容,比如為第三個實例增加一個 role: sd 的標簽,不用重新加載 Prometheus 配置,Prometheus 將 watch 該文件,并自動接收任何變化。
注意:當在生產(chǎn)環(huán)境 Prometheus 服務(wù)器中改變 file_sd 目標文件時,需要確保改變是原子的,以避免重新加載出現(xiàn)錯誤,最好的方法是在一個單獨的位置創(chuàng)建更新的文件,然后將其重命名為目標文件名(使用 mv 命令或 rename() 系統(tǒng)調(diào)用)。
這樣我們就完成了基于文件的通用服務(wù)發(fā)現(xiàn)機制,可以讓我們動態(tài)地改變 Prometheus 的監(jiān)控目標,而不需要重新啟動或重新加載 Prometheus 服務(wù)。當然除了基于 Consul 和文件的服務(wù)發(fā)現(xiàn)之外,更多的時候我們會在 Kubernetes 環(huán)境下面使用 Prometheus,由于這部分內(nèi)容比較獨立,后續(xù)我們再進行單獨講解(其實前面已經(jīng)詳細介紹過了)。