服務發如今Wikipedia的描述是:Service discovery is the automatic detection of devices and services offered by these devices on a computer network.
git
換句話說,它容許應用程序動態發現服務,而不是在應用程序配置中靜態定義服務。github
對於Prometheus,可使用多種方法進行服務發現,包括雲提供商API(例如AWS,Azure,GCE,Openstack),基於DNS的發現(使用SRV記錄)以及查詢Kubernetes API中正在運行的服務。web
可想而知,在目前雲原生環境下,應用具有高度彈性,經過靜態配置監控目標的行爲是多麼的低效。json
固然Prometheus 提供了Hotreload機制,在配置文件變動的時候,能夠通知Prometheus進行reload。並且在reload的過程當中,服務不會停機後端
熱更新的加載方法有兩種:服務器
固然新版本的Prometheus 的熱加載功能默認是關閉的,你須要在Prometheus的啓動參數中,添加以下參數:架構
--web.enable-lifecycle
app
可是這種方式,並非最優雅的,你須要維護整個配置文件。負載均衡
除靜態配置以外,Prometheus 已經支持了以下的服務發現方式:curl
# List of Azure service discovery configurations. azure_sd_configs: [ - <azure_sd_config> ... ] # List of Consul service discovery configurations. consul_sd_configs: [ - <consul_sd_config> ... ] # List of DNS service discovery configurations. dns_sd_configs: [ - <dns_sd_config> ... ] # List of EC2 service discovery configurations. ec2_sd_configs: [ - <ec2_sd_config> ... ] # List of OpenStack service discovery configurations. openstack_sd_configs: [ - <openstack_sd_config> ... ] # List of file service discovery configurations. file_sd_configs: [ - <file_sd_config> ... ] # List of GCE service discovery configurations. gce_sd_configs: [ - <gce_sd_config> ... ] # List of Kubernetes service discovery configurations. kubernetes_sd_configs: [ - <kubernetes_sd_config> ... ] # List of Marathon service discovery configurations. marathon_sd_configs: [ - <marathon_sd_config> ... ] # List of AirBnB's Nerve service discovery configurations. nerve_sd_configs: [ - <nerve_sd_config> ... ] # List of Zookeeper Serverset service discovery configurations. serverset_sd_configs: [ - <serverset_sd_config> ... ] # List of Triton service discovery configurations. triton_sd_configs: [ - <triton_sd_config> ... ]
下圖是一個Prometheus + consul sd 的架構。對於線上環境咱們可能會劃分爲:dev, stage, prod不一樣的集羣。每個集羣運行多個主機節點,每一個服務器節點上運行一個Node Exporter實例。Node Exporter實例會自動註冊到Consul中,而Prometheus則根據Consul返回的Node Exporter實例信息動態的維護Target列表,從而向這些Target輪詢監控數據。
固然目前官方對於增長新的服務發現方式比較慎重,與Alertmanager 通知類型狀況相似,官方不但願新的不穩定服務發現方式會影響Prometheus自身的穩定性。
可以與其餘SD機制(例如Docker Swarm)集成是源源不斷的需求。爲了解決這個問題,最近,Prometheus存儲庫中的文檔目錄進行了一些小的代碼更改,並提供了一個示例,以實現自定義服務發現集成,而無需將其合併到Prometheus主分支中。
例如,我在實際落地Prometheus的工程中,增長了下面兩種服務發現方式:
官方推薦的方式:按照官方的接口約定,實現新的服務發現方式,將發現的目標和標籤寫到文件中,而後結合prometheus自己支持的file_sd方式。Prometheus會按期到指定文件中獲取最新的目標。
以下所示:
scrape_configs: - job_name: "custom-sd" scrape_interval: "15s" file_sd_configs: - files: - /path/to/custom_sd.json
Adapter
首先了解一下adapter.go文件,您能夠複製此文件以實現自定義SD實現。
// Adapter runs an unknown service discovery implementation and converts its target groups // to JSON and writes to a file for file_sd. type Adapter struct { ctx context.Context disc discovery.Discoverer groups map[string]*customSD manager *discovery.Manager output string name string logger log.Logger } // Run starts a Discovery Manager and the custom service discovery implementation. func (a *Adapter) Run() { go a.manager.Run() a.manager.StartCustomProvider(a.ctx, a.name, a.disc) go a.runCustomSD(a.ctx) }
Adapter利用Discovery.Manager
在goroutine中啓動自定義SD提供程序的Run函數。Manager有一個通道,自定義SD將向其發送更新。這些更新包含SD目標。groups字段包含全部目標和標籤。
type customSD struct { Targets []string `json:"targets"` Labels map[string]string `json:"labels"` }
存在這個customSD
結構主要是爲了幫助咱們將內部Prometheus targetgroup.Group
結構轉換爲JSON以用於file_sd
格式。
運行時,Adapter將在通道上監聽來自咱們的自定義SD實現的更新,接收到更新後,它將解析targetgroup.Groups
到另外一個映射[string]* customSD
中,並將其存儲在Adapter,若是二者不一樣,咱們將新組分配給Adapter結構,並將它們做爲JSON寫入輸出文件中。
自定義SD實現
如今咱們要實際使用Adapter來實現咱們本身的自定義SD。完整的工做示例位於此處的examples目錄中。
在這裏,您能夠看到咱們導入Adapter代碼「 github.com/prometheus/prometheus/documentation/examples/custom-sd/adapter」以及其餘一些Prometheus庫。爲了編寫自定義SD,咱們須要一個實現Discoverer接口:
// Discoverer provides information about target groups. It maintains a set // of sources from which TargetGroups can originate. Whenever a discovery provider // detects a potential change, it sends the TargetGroup through its channel. // // Discoverer does not know if an actual change happened. // It does guarantee that it sends the new TargetGroup whenever a change happens. // // Discoverers should initially send a full set of all discoverable TargetGroups. type Discoverer interface { // Run hands a channel to the discovery provider(consul,dns etc) through which it can send // updated target groups. // Must returns if the context gets canceled. It should not close the update // channel on returning. Run(ctx context.Context, up chan<- []*targetgroup.Group) }
咱們實際上只須要實現一個函數 Run(ctx context.Context,up chan <-[] * targetgroup.Group)
。這是Adapter代碼中的管理器將在goroutine中調用的函數。Run函數包含了知道什麼時候退出的上下文,並傳遞了用於發送目標組更新的通道。
查看提供的示例中的Run函數,咱們能夠看到在另外一個SD的實現中須要作的一些關鍵事情。
若是實際場景中,公司已經有統一的服務註冊中心或是配置中心,那麼徹底能夠自定義SD,這樣的好處是,利用了現有的基礎設施,實現無縫對接。
另一點是,Prometheus 中kubernetes SD的方式,對於容器化部署的業務,更加簡單。