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 

image-20211110113838047

[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脚本语法

image-20211110114342150

若出现此错误:

Multiple private IPv4 addresses found. Please configure one with‘bind’ and/or ‘advertise’.
说明:出现这个问题的原因是,有多张网卡,所以就有了多个ip4的地址,解决方案,就是绑定ip地址到局域网卡,在这里插入图片描述
加上 -bind 192.168.xxx.xxx 参数即可

image-20211110114433000

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  #注册服务

image-20211110120129250

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


image.png

添加新标签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

image.png

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

image.png

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

image.png

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

image.png

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

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐