服务发如今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的方式,对于容器化部署的业务,更加简单。