Prometheus 通过 consul 实现自动服务发现
1. Consul 介绍Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。之前我们通过 Prometheus 实现监控,当新增一个 Target 时,需要变更服务器上的配置文件,即使使用 file_sd_configs 配置,也需
1. Consul 介绍
Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。之前我们通过 Prometheus 实现监控,当新增一个 Target 时,需要变更服务器上的配置文件,即使使用 file_sd_configs 配置,也需要登录服务器修改对应 Json 文件,会非常麻烦。不过 Prometheus 官方支持多种自动服务发现的类型,其中就支持 Consul。
2. Consul安装配置
其中 Prometheus 安装配置这里不过多赘述,详细请参考这里 Prometheus企业级监控入门
而 Consul 安装很方便,官网 提供各个系统版本二进制安装包,解压安装即可,同时也可以通过 Docker 来快速安装。
[root@grafana ~]# wget https://releases.hashicorp.com/consul/1.10.3/consul_1.10.3_linux_amd64.zip
[root@grafana ~]# mv consul_1.10.3_linux_amd64.zip /usr/local/
[root@grafana local]# unzip consul_1.10.3_linux_amd64.zip
[root@grafana local]# mkdir -p /data/consul /opt/logs/consul
[root@grafana local]# nohup ./consul agent -dev -client=0.0.0.0 -data-dir=/data/consul -bind=0.0.0.0 -log-file=/opt/logs/consul/consul.log -log-rotate-max-files=3 &
server
: 以server身份启动。bootstrap-expect
:集群要求的最少server数量,当低于这个数量,集群即失效。data-dir
:data存放的目录,更多信息请参阅consul数据同步机制node
:节点id,在同一集群不能重复。bind
:监听的ip地址。client
:客户端的ip地址(0.0.0.0表示不限制)&
:在后台运行,此为linux脚本语法
若出现此错误:
Multiple private IPv4 addresses found. Please configure one with‘bind’ and/or ‘advertise’.
说明:出现这个问题的原因是,有多张网卡,所以就有了多个ip4的地址,解决方案,就是绑定ip地址到局域网卡,
加上 -bind 192.168.xxx.xxx 参数即可
3. API 注册服务到 Consul
3.1 注册服务
[root@prometheus prometheus]# cat /tmp/request.json
{
"ID":"prometheus-143", #自定义
"Name":"monitor", #自定义
"Address":"192.168.153.143", #写自己服务的ip
"Port": 9090, #写自己服务的port
"Tags": ["prometheus"],
"Check":{
"HTTP":"http://192.168.153.143:9090/-/healthy", #写自己服务的ip和端口
"Interval":"10s" #每10s一检测
}
}
注:
name:consul的service注册名称
id:consul的实例名称
address:监控地址ip
port:监控的端口号
tags:标签名
checks:检查的节点的路径
[root@prometheus ~]# curl -XPUT http://192.168.153.205:8500/v1/agent/service/register -d@/tmp/request.json #注册服务
3.2 注销服务
如果要注销掉某个服务,可以通过如下 API 命令操作,例如注销上边添加的 monitor 服务(删除需要添加的是上面定义的 consul的实例名称,也就是id)
[root@prometheus ~]# curl -X PUT http://192.168.153.205:8500/v1/agent/service/deregister/prometheus-143
3.3 配置 Prometheus 实现自动服务发现
在prometheus中配置服务自动发现,去读取consul中配置的服务器,只要consul有新的服务注册,prometheus也会更新节点,在prometheus.yml中修改为
- job_name: 'consul-node-exporter'
consul_sd_configs: #配置使用 Consul 服务发现类型
- server: 'ip:8500' #consul的服务地址,这里跟上边要对应上。
- services: ["monitor"] #匹配consul定义的Name
配置完毕后,重启 Prometheus 服务,此时可以通过 Prometheus UI 页面的 Targets 下查看是否配置成功。
[root@prometheus ~]# systemctl restart prometheus
可以看到,在 Targets 中能够成功的自动发现 Consul 中的 Services 信息,后期需要添加新的 Targets 时,只需要通过 API 往 Consul 中注册服务即可,Prometheus 就能自动发现该服务,是不是很方便。
不过,我们会发现有如下几个问题:
- 默认只显示 job 及 instance 两个标签,其他标签都默认属于 before relabeling 下,有些必要的服务信息,也想要在标签中展示,该如何操作呢?
- 如果需要自定义一些标签,例如 team、group、project 等关键分组信息,方便后边 alertmanager 进行告警规则匹配,该如何处理呢?
- 所有 Consul 中注册的 Service 都会默认加载到 Prometheus 下配置的 consul_prometheus 组,如果有多种类型的 exporter,如何在 Prometheus 中配置分配给指定类型的组,方便直观的区别它们?
以上问题,我们可以通过 Prometheus 配置中的 relabel_configs 参数来解决。
4. Relabeling机制
4.1 标签重写概念
标签重写配置(relabel_config) 是实现的是对结果的标签重写、数据丢弃等操作,其功能非常强大,也属于 prometheus配置中比较复杂的部分。标签按名称的格式分为两类:
- 双下划线开头的 __ 为临时标签,在刚刚采集的数据中是存在的,但是经过一系列的
reblabel_confg
操作后,双下划线标签将被丢弃,不会入库。 - 非双下划线开头的标签会被正常入库。
每一个endpoint, 在relabel之前,都至少存在: job
、 __address__
、 __metrics_path__
、 __scheme__
,在 relabel 之后,这些双下划线的 label 不会入库。对于 relabel 中,产生的临时标签规范建议使用 __tmp 开头标签命名
在Prometheus所有的Target实例中,都包含一些默认的Metadata标签信息。可以通过Prometheus UI的Targets页面中查看这些实例的Metadata标签的内容:
默认情况下,当Prometheus加载Target实例完成后,这些Target时候都会包含一些默认的标签:
__address__
:当前Target实例的访问地址:__scheme__
:采集目标服务访问地址的HTTP Scheme,HTTP或者HTTPS__metrics_path__
:采集目标服务访问地址的访问路径__param_<name>
:采集任务目标服务的中包含的请求参数
4.2 配置文件
# 串联一组标签的值,用于后续操作
[ source_labels: '[' <labelname> [, ...] ']' ]
# source_labels 中各个标签值的拼接符
[ separator: <string> | default = ; ]
# 替换的结果会赋值给目标标签
[ target_label: <labelname> ]
# 匹配source_labels拼接后的值,系统会自动进行首尾锚定,去除锚定使用 .*<regex>.*
# 该正则表达式规范:https://github.com/google/re2/wiki/Syntax
# 分组的值可以被replacement引用($1,$2...)
[ regex: <regex> | default = (.*) ]
# 对source_labels的hash进行取模时指定的被除数
[ modulus: <int> ]
# 执行替换操作,可以引用正则表达式中的分组
[ replacement: <string> | default = $1 ]
# 执行的动作。支持: replace,drop,keep,labelmap,labeldrop,labelkeep,hashmod
[ action: <relabel_action> | default = replace ]
详细 relabel_configs
配置及说明可以参考 relabel_config 官网说明,这里我简单列举一下里面每个 relabel_action 的作用,方便下边演示。
replace
: 根据 regex 的配置匹配 source_labels 标签的值(注意:多个 source_label 的值会按照 separator 进行拼接),并且将匹配到的值写入到 target_label 当中,如果有多个匹配组,则可以使用 ${1}, ${2} 确定写入的内容。如果没匹配到任何内容则不对 target_label 进行重新, 默认为 replace。keep
: 丢弃 source_labels 的值中没有匹配到 regex 正则表达式内容的 Target 实例drop
: 丢弃 source_labels 的值中匹配到 regex 正则表达式内容的 Target 实例
hashmod
: 将 target_label 设置为关联的 source_label 的哈希模块labelmap
: 根据 regex 去匹配 Target 实例所有标签的名称(注意是名称),并且将捕获到的内容作为为新的标签名称,regex 匹配到标签的的值作为新标签的值labeldrop
: 对 Target 标签进行过滤,会移除匹配过滤条件的所有标签labelkeep
: 对 Target 标签进行过滤,会移除不匹配过滤条件的所有标签
4.3 relabel_configs 配置案例
prometheus 中难以理解的是标签重写规则,本节针对不同 action 进行 target 的标签重写,实验环境如下: 在 prometheus-72 上启动三个 node_exporter 实例,分别监听 8081, 8082, 8083 端口,prometheus-72 从这三个 node_exporter 中采集数据。
[root@prometheus-72 ~]# jobs
[1] Running /opt/apps/node_exporter/node_exporter --log.level=error --web.listen-address=":8081" &
[2]- Running /opt/apps/node_exporter/node_exporter --log.level=error --web.listen-address=":8082" &
[3]+ Running /opt/apps/node_exporter/node_exporter --log.level=error --web.listen-address=":8083" &
4.3.1 action: replace
重写规则之前:
[root@prometheus-72 prometheus]# cat prometheus.yml
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
env: dev
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
添加新标签host,使其格式为: master-dev-72
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
env: dev
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- source_labels: ["role", "env", "__address__"]
target_label: host
regex: (.+);(.+);([0-9]{1,3}\.){3}([0-9]+):[0-9]+ # source_labels默认 ; 拼接
replacement: $1-$2-$4
4.3.2 action: keep
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
env: dev
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- source_labels: ["role", "env", "__address__"]
target_label: host
regex: (.+);(.+);([0-9]{1,3}\.){3}([0-9]+):[0-9]+ # source_labels默认 ; 拼接
replacement: $1-$2-$4
- source_labels: ["env"] # 仅保留 env=prod 的target
regex: prod
action: keep
4.3.3 action: drop
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
env: dev
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- source_labels: ["role", "env", "__address__"]
target_label: host
regex: (.+);(.+);([0-9]{1,3}\.){3}([0-9]+):[0-9]+ # source_labels默认 ; 拼接
replacement: $1-$2-$4
- source_labels: ["env"] # 删除 lable_name 为env,切value为prod的target
regex: prod
action: drop
4.3.4 action: labelkeep
尽量不要删除 __ 的标签,比如删了 address 标签会导致 instance 生成异常,进而导致无法获取target信息
[root@prometheus-72 prometheus]# cat prometheus.yml
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- regex: (__|role).* # 非临时标签仅保留 role
action: labelkeep
4.3.5 action: labeldrop
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- regex: env # 将env标签删除,并是上次target
action: labeldrop
4.3.6 action: labelmap
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- regex: __(.+)__ # 将所有双下划线的标签名改为非双下划线的标签名称
action: labelmap
4.3.7 action: hashmod
当一个job中监控目标数量太多时(自动发现中容易出现),将任务分散到不同的机器上。hashmod会将 source_labels值哈希后采用 modulus 取余数,并赋值到一个标签,然后在接下来的relabel中进行保留或者剔除,这样能实现每个prometheus采集一部分target数据。下面案例中,其余后 __tmp_hash_value 值有 0、1、2,因此将target分为三组,可以由三个不同的prometheus去获取监控指标。
global:
scrape_interval: 60s
external_labels:
monitor: 'codelab-monitor'
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ["10.4.7.72:8081"]
labels:
app: app-01
role: master
- targets: ["10.4.7.72:8082"]
labels:
app: app-02
env: prod
role: master
- targets: ["10.4.7.72:8083"]
labels:
app: app-02
env: prod
role: slave
relabel_configs:
- source_labels: ["__address__"]
action: hashmod
modulus: 3
target_label: __tmp_hash_value
- source_labels: [__tmp_hash_value]
regex: "0"
action: drop
5. 配置 relabel_configs 实现自定义标签及分类
Prometheus 加载 Targets 后,这些 Targets 会自动包含一些默认的标签,Target 以 __
作为前置的标签是在系统内部使用的,这些标签不会被写入到样本数据中。眼尖的会发现,每次增加 Target 时会自动增加一个 instance 标签,而 instance 标签的内容刚好对应 Target 实例的 __address__
值,这是因为实际上 Prometheus 内部做了一次标签重写处理,默认 __address__
标签设置为 <host>:<port>
地址,经过标签重写后,默认会自动将该值设置为 instance 标签,所以我们能够在页面看到该标签。
4.1 问题一
我们可以配置 relabel_configs 来实现标签过滤,只加载符合规则的服务。以上边为例,可以通过过滤 __meta_consul_tags 标签为 test 的服务,relabel_config 向 Consul 注册服务的时候,只加载匹配 regex 表达式的标签的服务到自己的配置文件。修改 prometheus.yml 配置如下:
...
- job_name: 'consul-prometheus'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*test.*
action: keep
解释下,这里的 relabel_configs 配置作用为丢弃源标签中 __meta_consul_tags 不包含 test 标签的服务,__meta_consul_tags 对应到 Consul 服务中的值为 “tags”: [“test”],默认 consul 服务是不带该标签的,从而实现过滤。重启 Prometheus 可以看到现在只获取了 node-exporter-172.30.12.167 这个服务了。
4.2 问题二和问题三
问题二和问题三可以归为一类,就是将系统默认标签或者用户自定义标签转换成可视化标签,方便查看及后续 Alertmanager 进行告警规则匹配分组。不过要实现给服务添加自定义标签,我们还得做一下修改,就是在注册服务时,将自定义标签信息添加到 Meta Data 数据中,具体可以参考 [这里](Consul Service - Agent HTTP API) 官网说明,下边来演示一下如何操作。
新建 consul-0.json 如下:
$ vim consul-0.json
{
"ID": "node-exporter",
"Name": "node-exporter-172.30.12.167",
"Tags": [
"test"
],
"Address": "172.30.12.167",
"Port": 9100,
"Meta": {
"app": "spring-boot",
"team": "appgroup",
"project": "bigdata"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:9100/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
说明一下:该 Json 文件为要注册的服务信息,同时往 Meta 信息中添加了 app=spring-boot,team=appgroup,project=bigdata 三组标签,目的就是为了方便告警分组使用。执行如下命令进行注册:
$ curl --request PUT --data @consul-0.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
注册完毕,通过 Consul Web 管理页面可以查看到已注册成功,并且包含了 Meta 信息。
然后修改 prometheus.yml 配置如下:
...
- job_name: 'consul-prometheus'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*test.*
action: keep
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
解释一下,增加的配置作用为匹配 _meta_consul_service_metadata 开头的标签,将捕获到的内容作为新的标签名称,匹配到标签的的值作为新标签的值,而我们刚添加的三个自定义标签,系统会自动添加 __meta_consul_service_metadata_app=spring-boot、__meta_consul_service_metadata_team=appgroup、__meta_consul_service_metadata_project=bigdata 三个标签,经过 relabel 后,Prometheus 将会新增 app=spring-boot、team=appgroup、project=bigdata 三个标签。重启 Prometheus 服务,可以看到新增了对应了三个自定义标签。
4.3 问题四
问题四,将自动发现的服务进行分类,本质上跟上边的处理方式一致,可以添加自定义的标签方式,通过标签来区分,二可以通过服务 Tag 来进行匹配来创建不同的类型 exporter 分组。这里我以第二种为例,通过给每个服务标记不同的 Tag,然后通过 relabel_configs 来进行匹配区分。我们来更新一下原 node-exporter-172.30.12.167 服务标签,同时注册一个其他类型 exporter 的服务如下:
$ vim consul-1.json
{
"ID": "node-exporter",
"Name": "node-exporter-172.30.12.167",
"Tags": [
"node-exporter"
],
"Address": "172.30.12.167",
"Port": 9100,
"Meta": {
"app": "spring-boot",
"team": "appgroup",
"project": "bigdata"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:9100/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
# 更新注册服务
$ curl --request PUT --data @consul-1.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
$ vim consul-2.json
{
"ID": "cadvisor-exporter",
"Name": "cadvisor-exporter-172.30.12.167",
"Tags": [
"cadvisor-exporter"
],
"Address": "172.30.12.167",
"Port": 8080,
"Meta": {
"app": "docker",
"team": "cloudgroup",
"project": "docker-service"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:8080/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
# 注册服务
$ curl --request PUT --data @consul-2.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
说明一下,我们更新了原 node-exporter-172.30.12.167 服务的标签为 node-exporter,同时注册一个新类型 cadvisor-exporter-172.30.12.167 服务,并设置标签为 cadvisor-exporter,以示区别。注册完毕,通过 Consul Web 控制台可以看到成功注册了这两个服务。
最后,我们修改 prometheus.yml 配置如下:
...
- job_name: 'consul-node-exporter'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*node-exporter.*
action: keep
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
- job_name: 'consul-cadvisor-exproter'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags] #service源标签
regex: .*cadvisor-exporter.* #匹配为“cadvisor-exporter”的service
action: keep #执行的动作
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
这里需要根据每种类型的 exporter 新增一个关联 job,同时 relabel_configs 中配置以 Tag 来做匹配区分。重启 Prometheus 服务,可以看到服务已经按照类型分类了,方便查看。
4.4 consul 可以使用的元标签
__meta_consul_address:目标的地址
__meta_consul_dc:目标的数据中心名称
__meta_consul_tagged_address_<key>:每个节点标记目标的地址键值
__meta_consul_metadata_<key>:目标的每个节点元数据键值
__meta_consul_node:为目标定义的节点名称
__meta_consul_service_address:目标的服务地址
__meta_consul_service_id:目标的服务ID
__meta_consul_service_metadata_<key>:目标的每个服务元数据键值
__meta_consul_service_port:目标的服务端口
__meta_consul_service:目标所属服务的名称
__meta_consul_tags:标记分隔符连接的目标的标记列表
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)