跳转至

基于 Consul 的服务发现

Consul 是由 HashiCorp 开发的一个支持多数据中心的分布式服务发现和键值对存储服务的开源软件,是一个通用的服务发现和注册中心工具,被大量应用于基于微服务的软件架构当中。

接下来我们就来尝试使用 Prometheus 基于 Consul 的服务发现来监控前面的 3 个 demo 服务:

192.168.31.46:10000
192.168.31.46:10001
192.168.31.46:10002

我们将 demo 服务注册到 Consul,然后配置 Prometheus 从 Consul 中发现演示服务实例,并使用 Relabeling 操作来过滤调整目标标签。关于 Consul 本身的使用可以查看官方文档 https://learn.hashicorp.com/consul 了解更多。

consul

安装配置 Consul

在页面 https://www.consul.io/downloads 下载符合自己系统的安装文件,比如我们这里是 Linux 系统,使用下面命令下载安装即可:

☸ ➜ 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)

当执行 consul 命令后正常有命令提示,证明已经安装完成。接着创建一个用于注册 demo 服务的 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 中进行动态注册服务,但是这里我们只是简单演示 Prometheus 基于 Consul 的服务发现,这里只使用 Consul 配置文件静态注册服务即可。Consul 允许使用 JSON 中的 meta属性将 key-value 元数据与每个注册的服务实例相关联,比如这里我们配置的 env 属性和部署环境 production 或 staging 进行关联,后面我们可以通过使用 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 参数指定了客户端绑定的 IP 地址,默认为 127.0.0.1。除了我们注册的 3 个 demo 服务之外,Consul agent 还会将自己注册为一个名为 consul 的服务,我们可以在浏览器中访问 http://<nodeip>:8500 查看注册的服务。

consul ui

在 Consul UI 页面中可以看到有 consuldemo 两个 Service 服务。

配置 Consul 自动发现

上面我们通过 Consul 注册了 3 个 demo 服务,接下来我们将配置 Prometheus 通过 Consul 来自动发现 demo 服务。

在 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 的抓取任务,通过 consul_sd_configs 配置用于自动发现的 Consul 服务地址,然后使用 relabel_configs 进行了重新标记配置,首先只保留服务名称为 demo,且健康状态为 passing 的,否则也会抓取 Consul Agent 本身,而它自身是不提供 metrics 接口数据的,另外还使用 labelmap 进行了标签映射,将所有 Consul 元标签映射到 Prometheus 中以 consul_ 为前缀的标签中。

配置完成后重新启动 Prometheus,然后重新查看 Prometheus 页面上的 targets 页面,验证上面的配置是否存在:

targets

正常情况下是可以看到会有一个 consul-sd-demo 的任务,下面有 3 个自动发现的抓取目标。

我们将鼠标悬停在 Labels 标签区域就可以看到目标任务在重新标记 Relabeling 之前的原始标签。比如我们将查看第一个 demo 实例在 Relabel 之前包含如下所示的这些原始标签:

raw labels

通过查看网络请求接口 http://<promtheus addr>/api/v1/targets?state=active 也可以获取对应的原始标签数据:

{
  "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_healthpassing 状态的抓取任务。然后使用 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__ 转变而来的。由于没有重新修改 __metrics_path____scheme__ 标签,所以默认的抓取目标就是通过 HTTP 端点 /metrics 进行抓取。

现在如果我们将 demo1 这个服务杀掉,则在 Consul 中注册的服务就会出现一个不健康的实例:

unhealth

当然此时 Prometheus 中就只剩下两个正常 demo 服务的实例了:

targets

当服务正常后就又可以自动发现对应的服务了。这样我们就完成了 Prometheus 基于 Consul 的一个简单的自动发现配置。