一、Relabeling 重新标记
Relabeling 重新标记用于配置 Prometheus 元信息的方式,它是转换和过滤 Prometheus 中 label 标签对象的核心
1、概述
Prometheus 发现、抓取和处理不同类型的 label 标签对象,根据标签值操作或过滤这些对象非常有用,比如:
- 只监视具有特定服务发现注解的某些目标,通常在服务发现中使用
- 向目标抓取请求添加 HTTP 查询参数
- 仅存储从指定目标中提取样本的子集
- 将抓取序列的两个标签值合并为一个标签
Relabeling 是作为一系列转换步骤实现的,我们可以在 Prometheus 的配置文件中应用这些步骤来过滤或修改标记对象,我们可以对一下类型的标记对象应用 Relabeling 操作:
- 发现的抓取目标(relabel_configs)
- 抓取的单个样本(metric_relabel_configs)
- 发送给 Alertmanager 的报警(alert_relabel_configs)
- 写到远程存储的样本(write_relabel_configs)
平时在配置监控目标的时更多的会使用 relabel_configs 与 metric_relabel_configs 两个配置,采集数据之前,通过 relabel_configs,采集数据之后,写入存储之前,通过 metric_relabel_configs 进行配置。
所有这些 relabeling 配置块都是相同类型的 relabel_config,每个配置块都由一个规则列表组成,这些规则依次应用与每个标记的对象。
例如,一个 relabeling 规则可以根据正则表达式的匹配来保留或丢弃一个对象,可以修改其标签,也可以将一整组标签映射到另一组。一旦一个 relabeling 步骤决定放弃一个有标签的对象,就不会对这个对象执行进一步的 relabeling 步骤,它将从输出列表中删除。
2、隐藏的标签与元数据
以双下划线__开头的标签属于特殊的标签,它们在重新标记后会被删除。标记对象的来源最初可以附加这些隐藏的标签,以提供关于标记对象的额外元数据,这些特殊的标签可以在 relabeling 阶段被用来对对象的标签进行修改
对于抓取指标,其中就包含一些隐藏的标签,可以用来控制目标应该如何被抓取。
__address__
:包含应该被抓取目标的地址,它最初默认为服务发现机制提供的 :,如果在此之前没有明确地将实例标签 instance 设置为其他值,那么在 relabeling 之后,Prometheus 会将 instance 标签设置为 address 的值。__scheme__
:抓取目标的请求模式,包括 http 与 https,默认为 http。__metrics_path__
:表示用于采集指标的 HTTP 路径,默认为 /metrics。__param_<name>
: 包含 HTTP 查询参数名称和它们的值。
上面的这些标签都可以使用 relabeling 规则来设置或覆盖,这样就可以为抓取目标进行自定义抓取行为。
此外,服务发现机制也可以提供一组以 _meta 开头的标签,包含关于目标的特定发现元数据。例如,当发现 Kubernetes 集群中的 pod 时,Kubernetes 服务发现引擎将为每个 pod 目标提供一个 __meta_kubernetes_pod_name 的标签,包含被发现的 pod 的名字,以及一个 __meta_kubernetes_pod_ready 标签,表明 pod 是否处于就绪状态,关于服务发现生成的元标签可以查看官方文档 https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config 了解更多。
如果一个 relabeling 步骤需要将一个值保存到一个临时标签中(以便在随后的步骤中处理),那么我们可以使用 __tmp 标签名称前缀进行标记,以 __tmp 开通的标签是不会被 Prometheus 本身使用的。
3、规则
Relabeling 规则主要由以下的一些配置属性组成,但对于每种类型的操作,只使用这些字段的一个子集。
- action:执行的 relabeling 动作,可选值包括 replace、keep、drop、hashmod、labelmap、labeldrop 或者 labelkeep,默认值为 replace。
- separator:分隔符,一个字符串,用于在连接源标签 source_labels 时分隔它们,默认为 ; 。
- source_labels:源标签,使用配置的分隔符串联的标签名称列表,并与提供的正则表达式进行匹配。
- target_label:目标标签,当使用 replace 或者 hashmod 动作时,应该被覆盖的标签名。
- regex:正则表达式,用于匹配串联的源标签,默认为 (.*),匹配任何源标签。
- modulus:模数,串联的源标签哈希值的模,主要用于 Prometheus 水平分片。
- replacement:replacement 字符串,写在目标标签上,用于替换 relabeling 动作,它可以参考由 regex 捕获的正则表达式捕获组。
3.1、设置或替换标签值
Relabeling 的一个常见操作就是设置或者覆盖一个标签的值,我们可以通过 replace 这个操作来完成,如果没有指定 action 字段,则默认就是 replace
一个 replace 动作的规则配置方式如下所示:
action: replace
source_labels: [<source label name list>]
separator: <source labels separator> # 默认为 ';'
regex: <regular expression> # 默认为 '(.*)' (匹配任何值))
replacement: <replacement string> # 默认为 '$1' (使用第一个捕获组作为 replacement)
target_label: <target label>
该操作按顺序执行以下步骤:
- 使用提供的 separator 分隔符将 source_labels 中的标签列表值连接起来
- 测试 regex 中的正则表达式是否与上一步连接的字符串匹配,如果不匹配,就跳到下一个 relabeling 规则,不替换任何东西
- 如果正则匹配,就提取正则表达式捕获组中的值,并将 replacement 字符串中对这些组的引用($1, $2, …)用它们的值替换
- 把经过正则表达式替换的 replacement 字符串作为 target_label 标签的新值存储起来
replace 操作的示例
3.1-1、设置一个固定的标签值
将一个标签设置为一个固定的值,比如把 env 标签设置为 production
action: replace
replacement: production
target_label: env
3.1-2、替换抓取任务端口(用固定的 80 端口来替换 address 标签的端口)
这里替换的源标签为 address,然后通过正则表达式 ([^:]+)(?::\d+)? 进行匹配,这里有两个捕获组,第一个匹配的是 host($1),第二个匹配的是端口($2),所以在 replacement 字符串中我们保留第一个捕获组 $1,然后将端口更改为 80,这样就可以将 address 的实例端口更改为 80 端口,然后重新写会 address 这个目标标签
action: replace
source_labels: [__address__]
regex: ([^:]+)(?::\d+)? # 第一个捕获组匹配的是 host,第二个匹配的是 port 端口。
replacement: '$1:80'
target_label: __address__
3.1-3、保留或丢弃对象
Relabeling 另一个常见的用例就是过滤有标签的对象,keep 或 drop 这两个动作可以来完成,使用这两个操作,可以帮助完成如下的一些操作:
- 来自服务发现的哪些目标应该被抓取
- 从目标中抓取哪些指定的序列样本,或将其发送到远程存储
- 哪些报警要发送到 Alertmanager
一个 keep 动作的配置规则如下所示
action: keep
source_labels: [<source label name list>]
separator: <source labels separator> # 默认为 ';'
regex: <regular expression> # 默认为 '(.*)' (匹配任何值)
keep 操作同样按顺序执行如下步骤:
- 使用 separator 分隔符将 source_labels 中列出的标签值连接起来
- 测试 regex 中的正则表达式是否与上一步的连接字符串匹配
- 如果不匹配,该对象将从最终输出列表中删除
- 如果匹配,则保留该对象
drop 动作和 keep 类似,只是它是删除一个对象而不是保留。
同样接下来看一看 keep 和 drop 的示例
只抓取具有注解的目标
在服务发现的时候,可能需要抓取具有特定元数据标签的目标,例如,下面的配置让只抓取 Kubernetes 中具有 example.io/should_be_scraped=true 这个 annotation 的目标
action: keep
source_labels:
[__meta_kubernetes_service_annotation_example_io_should_be_scraped]
regex: true
Kubernetes 服务发现机制下面会将 labels 标签与 annotation 作为元信息输出到 Prometheus,这些元信息都包含 _meta 前缀,这里我们的配置就是保留具有 example.io/should_be_scraped 这个 annotation 标签,且值为 true 的目标。
只存储特定的指标
当使用 metric_relabel_configs 来控制目标的抓取方式时,我们可以使用下面的规则来只存储指标名称以 api_ 或 http_ 开头的指标
action: keep
source_labels: [__name__]
regex: '(api_|http_).*'
3.1-4、标签集映射
有时我们可能想把源标签的值映射到一组新的标签中去,这个时候就可以使用 labelmap 这个动作了。labelmap 最常用的使用场景就是从服务发现中获取一组隐藏的或临时的元数据标签,并将它们映射到新的目标标签中。
labelmap 动作的配置规则如下所示:
action: labelmap
regex: <regular expression> # 默认为 '(.*)'
replacement: <replacement string> # 默认为 '$1'
和前面的一些 action 不同,labelmap 是对标签名而不是标签值进行重新匹配和操作。labelmap 按顺序执行以下步骤:
- 将 regex 中的正则表达式与所有标签名进行匹配
- 将匹配的标签名的任何匹配值复制到由 replacement 字符串决定的新的标签名中
下面我们看一个使用 labelmap 映射 Kubernetes Service 标签的示例。当使用基于 Kubernetes 的服务发现来发现 pod 端点时,我们可能希望每个端点的最终目标标签也包含 Kubernetes Service 标签,这样可以更好的区分端点数据。Kubernetes 服务发现机制会将这些标签添加到 Prometheus 中去,标签名称格式为 meta_kubernetes_service_label,我们可以提取这些元数据标签中的 部分,并将相应的标签值映射到一组以 k8s 为前缀的新标签名称上,如下所示:
action: labelmap
regex: __meta_kubernetes_service_label_(.+)
replacement: 'k8s_$1'
通过上面的 labelmap 操作,regex 正则表达式中匹配标签名,然后将标签名对应的值复制到 k8s_$1 的新标签中,$1 就是匹配的标签名这个捕获组。
3.1-5、保留或删除标签
有的时候我们也有保留或删除一些标签的需求,比如有的目标在时间序列上提供了许多额外的标签,这些标签用途不大,这个时候我们就可以使用 labelkeep 和 labeldrop 这两个操作,使用这两个操作可以有选择地保留或删除一些标签。
labelkeep 的配置规则如下所示:
action: labelkeep
regex: <regular expression> # 默认为'(.*)'
一样 labelkeep 按顺序执行下面的步骤:
- 首先将 regex 中的正则表达式与所有标签名称进行匹配
- 它只保留那些匹配的标签
labeldrop 与 labelkeep 类似,只是它是删除那些匹配正则表达式的标签而不是保留。
下面我们看一看 labelkeep/labeldrop 操作的简单示例
从报警中删除高可用副本标签
当运行两个相同的 Prometheus 作高可用的时候,通常两个服务器都被配置为有一个外部标签(通过全局配置选项 external_labels),表明它们代表哪个副本,例如:replica: A 和 replica: B,在从两个副本向同一个 Alertmanager 实例发送报警之前,Prometheus 需要删除这个副本标签,这样 Alertmanager 就不会把收到的报警看成不同的报警了,否则可能我们会收到两个同样的报警通知。这个时候我们就可以使用 labeldrop 来实现这个操作。
action: labeldrop
regex: replica
这条配置规则很简单的,就是匹配 replica 这个标签,然后执行 labeldrop 删除标签动作即可。
删除指标中不需要的标签
有的时候我们抓取的指标在每个时间序列上都附加了一些额外的标签,这些标签对于我们来说用处不大,还会增加 Prometheus 的存储压力,所以我们可以想办法删除不需要的额外标签。
比如现在我们想要删除一 info_ 开头的标签,我们可以使用下面的配置规则来完成。
action: labeldrop
regex: info_.*
同样也只是配置一个要删除的目标标签的正则表达式即可,只要匹配了的标签都会执行 labeldrop 操作将该标签进行删除。
3.2、标签值哈希和分片
在一些场景下我们可能需要运行多个几乎相同的 Prometheus 副本来横向扩展,每个副本只抓取部分目标,这样可以降低 Prometheus 的压力,在这种情况下 hashmod 操作有助于我们对目标进行分片操作。
hashmod 的配置规则如下所示:
action: hashmod
source_labels: [<source label name list>]
modulus: <modulus value>
target_label: <target label>
该操作按顺序执行下面的步骤:
- 首先使用分隔符将源标签集 source_labels 的值连接起来
- 计算连接后的字符串的哈希值
- 将 modulus 中提供的模数应用于哈希值,以将哈希值限制在 0 和modulus-1之间
- 将上一步的模数值存储在 target_label 目标标签中
使用 hashmod 的主要场景是将一个服务的整体目标进行分片,用于水平扩展 Prometheus,通过首先根据每个目标的一个或多个标签计算基于哈希的模数来实现的,然后只保留具有特定输出模数值的目标。比如为了根据 instance 标签对目标进行分片,只保留分片 2 的实例,我们可以把 hashmod 和 keep 结合起来操作
- action: hashmod
source_labels: [instance]
modulus: 10
target_label: __tmp_hashmod
- action: keep
source_labels: [__tmp_hashmod]
regex: 2
首先通过 hashmod 操作对 instance 标签进去哈希操作,将取模后的值存储在临时标签 __tmp_hashmod 中,然后通过第二个 keep 操作,只保留分片数为 2 的指标,这样就达到了分片的目的。
二、服务发现介绍
Prometheus 配置文件中可以通过一个 static_configs 来配置静态的抓取任务,但是在云环境、容器环境下,抓取目标地址是经常变动的,用静态的方式就不能满足这些场景。要监控系统能够动态感知这个变化,不能每次变动都去手动重新配置的,为了应对复杂的动态环境,Prometheus 也提供了与基础设施中的服务发现集成的功能
Prometheus 已经支持多种内置的服务发现机制:
- 发现云服务商的 VM 虚拟机
- Kubernetes 上的自动发现
- 通用的服务查找,例如 DNS、Consul、Zookeeper 或自定义发现机制
我们都可以通过 Prometheus 配置文件中的 scrape_config 部分进行配置,Prometheus 会不断更新动态的抓取目标列表,自动停止抓取旧的实例,开始抓取新的实例,Prometheus 特别适合运行于 Kubernetes 集群下面,可以自动发现监控目标。
此外大部分服务发现机制还会提供目标的一些元数据,通常都是带有 __ 的前缀, 比如标签、注解、服务名等等,可以在 relabeling 阶段使用这些元数据来过滤修改目标,这些元信息标签在重新标记阶段后被删除。
三、基于 Consul 的服务发现
Consul 是由 HashiCorp 开发的一个支持多数据中心的分布式服务发现和键值对存储服务的开源软件,是一个通用的服务发现和注册中心工具,被大量应用于基于微服务的软件架构当中。
尝试使用 Prometheus 基于 Consul 的服务发现来监控前面的 3 个 demo 服务:
192.168.0.160:10000
192.168.0.160:10001
192.168.0.160:10002
将 demo 服务注册到 Consul,然后配置 Prometheus 从 Consul 中发现演示服务实例,并使用 Relabeling 操作来过滤调整目标标签。关于 Consul 本身的使用可以查看官方文档 https://learn.hashicorp.com/consul 了解更多。
1、安装配置 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.0.160",
"port": 10000,
"meta": {
"env": "production"
},
"checks": [
{
"http": "http://192.168.0.160:10000/api/foo",
"interval": "1s"
}
]
},
{
"id": "demo2",
"name": "demo",
"address": "192.168.0.160",
"port": 10001,
"meta": {
"env": "production"
},
"checks": [
{
"http": "http://192.168.0.160:10001/api/foo",
"interval": "1s"
}
]
},
{
"id": "demo3",
"name": "demo",
"address": "192.168.0.160",
"port": 10002,
"meta": {
"env": "staging"
},
"checks": [
{
"http": "http://192.168.0.160: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
这里我们在启动命令后面使用 -client 参数指定了客户端绑定的 IP 地址,默认为 127.0.0.1。除了我们注册的 3 个 demo 服务之外,Consul agent 还会将自己注册为一个名为 consul 的服务,我们可以在浏览器中访问 http://:8500 查看注册的服务。在 Consul UI 页面中可以看到有 consul 和 demo 两个 Service 服务。
2、配置 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 页面,验证上面的配置是否存在
正常情况下是可以看到会有一个 consul-sd-demo 的任务,下面有 3 个自动发现的抓取目标。
我们将鼠标悬停在 Labels 标签区域就可以看到目标任务在重新标记 Relabeling 之前的原始标签。比如我们将查看第一个 demo 实例在 Relabel 之前包含如下所示的这些原始标签:
通过查看网络请求接口 http:///api/v1/targets?state=active|jq 也可以获取对应的原始标签数据:
{
"status": "success",
"data": {
"activeTargets": [
{
"discoveredLabels": {
"__address__": "192.168.0.160:10002",
"__meta_consul_address": "127.0.0.1",
"__meta_consul_dc": "dc1",
"__meta_consul_health": "passing",
"__meta_consul_node": "go-dev",
"__meta_consul_service": "demo",
"__meta_consul_service_address": "192.168.0.160",
"__meta_consul_service_id": "demo3",
"__meta_consul_service_metadata_env": "staging",
"__meta_consul_service_port": "10002",
"__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",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "consul-sd-demo"
},
"labels": {
"consul_env": "staging",
"instance": "192.168.0.160:10002",
"job": "consul-sd-demo"
},
"scrapePool": "consul-sd-demo",
"scrapeUrl": "http://192.168.0.160:10002/metrics",
"globalUrl": "http://192.168.0.160:10002/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:15.145314173+08:00",
"lastScrapeDuration": 0.003947196,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "192.168.0.160:10000",
"__meta_consul_address": "127.0.0.1",
"__meta_consul_dc": "dc1",
"__meta_consul_health": "passing",
"__meta_consul_node": "go-dev",
"__meta_consul_service": "demo",
"__meta_consul_service_address": "192.168.0.160",
"__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",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "consul-sd-demo"
},
"labels": {
"consul_env": "production",
"instance": "192.168.0.160:10000",
"job": "consul-sd-demo"
},
"scrapePool": "consul-sd-demo",
"scrapeUrl": "http://192.168.0.160:10000/metrics",
"globalUrl": "http://192.168.0.160:10000/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:16.109023592+08:00",
"lastScrapeDuration": 0.003511689,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "192.168.0.160:10001",
"__meta_consul_address": "127.0.0.1",
"__meta_consul_dc": "dc1",
"__meta_consul_health": "passing",
"__meta_consul_node": "go-dev",
"__meta_consul_service": "demo",
"__meta_consul_service_address": "192.168.0.160",
"__meta_consul_service_id": "demo2",
"__meta_consul_service_metadata_env": "production",
"__meta_consul_service_port": "10001",
"__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",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "consul-sd-demo"
},
"labels": {
"consul_env": "production",
"instance": "192.168.0.160:10001",
"job": "consul-sd-demo"
},
"scrapePool": "consul-sd-demo",
"scrapeUrl": "http://192.168.0.160:10001/metrics",
"globalUrl": "http://192.168.0.160:10001/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:12.119854362+08:00",
"lastScrapeDuration": 0.003453286,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "localhost:10000",
"__metrics_path__": "/metrics",
"__scheme__": "http",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "demo"
},
"labels": {
"instance": "localhost:10000",
"job": "demo"
},
"scrapePool": "demo",
"scrapeUrl": "http://localhost:10000/metrics",
"globalUrl": "http://go-dev:10000/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:14.045498791+08:00",
"lastScrapeDuration": 0.003576043,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "localhost:10001",
"__metrics_path__": "/metrics",
"__scheme__": "http",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "demo"
},
"labels": {
"instance": "localhost:10001",
"job": "demo"
},
"scrapePool": "demo",
"scrapeUrl": "http://localhost:10001/metrics",
"globalUrl": "http://go-dev:10001/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:11.57225173+08:00",
"lastScrapeDuration": 0.003987971,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "localhost:10002",
"__metrics_path__": "/metrics",
"__scheme__": "http",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "demo"
},
"labels": {
"instance": "localhost:10002",
"job": "demo"
},
"scrapePool": "demo",
"scrapeUrl": "http://localhost:10002/metrics",
"globalUrl": "http://go-dev:10002/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:11.625052716+08:00",
"lastScrapeDuration": 0.0036294,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
},
{
"discoveredLabels": {
"__address__": "localhost:9090",
"__metrics_path__": "/metrics",
"__scheme__": "http",
"__scrape_interval__": "5s",
"__scrape_timeout__": "5s",
"job": "prometheus"
},
"labels": {
"instance": "localhost:9090",
"job": "prometheus"
},
"scrapePool": "prometheus",
"scrapeUrl": "http://localhost:9090/metrics",
"globalUrl": "http://go-dev:9090/metrics",
"lastError": "",
"lastScrape": "2023-10-17T18:43:12.954501341+08:00",
"lastScrapeDuration": 0.006102573,
"health": "up",
"scrapeInterval": "5s",
"scrapeTimeout": "5s"
}
],
"droppedTargets": []
}
}
我们在 relabel_configs 中首先配置了一个 keep 操作,只保留原始标签 __meta_consul_service 值为 demo,且 __meta_consul_health 为 passing 状态的抓取任务。然后使用 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 进行抓取。
四、基于文件的服务发现
除了基于 Consul 的服务发现之外,Prometheus 也允许我们进行自定义的发现集成,可以通过 watch 一组本地文件来获取抓取目标以及标签信息,也就是我们常说的基于文件的服务发现方式。
基于文件的服务发现提供了一种更通用的方式来配置静态目标,并作为一个接口插入自定义服务发现机制。
它读取一组包含零个或多个 <static_config> 列表的文件,对所有定义的文件的变更通过磁盘监视被检测到并立即应用,文件可以以 YAML 或 JSON 格式提供。文件必须包含一个静态配置的列表:
JSON json [ { "targets": [ "<host>", ... ], "labels": { "<labelname>": "<labelvalue>", ... } }, ... ]
YAML yaml - targets: [ - '<host>' ] labels: [ <labelname>: <labelvalue> ... ]
文件内容也会在指定的刷新间隔时间内定期重新读取。
# Patterns for files from which target groups are extracted.
files:
[ - <filename_pattern> ... ]
# Refresh interval to re-read the files.
[ refresh_interval: <duration> | default = 5m ]
其中 <filename*pattern> 可以是一个以 .json、.yml 或 .yaml 结尾的路径,最后一个路径段可以包含一个匹配任何字符序列的 ,例如:my/path/tg_.json。
1、创建文件
接下来我们来创建一个用于服务发现的目标文件,在与 prometheus.yml 文件相同目录下面创建一个名为 targets.yml 的文件,内容如下所示
- targets:
- '192.168.0.160:10000'
- '192.168.0.160:10001'
labels:
env: production
- targets:
- '192.168.0.160:10002'
labels:
env: staging
该文件中我们列举了 3 个 demo 服务实例,给前两个实例添加上了 env=production 的标签,后面一个加上了 env=staging 的标签,当然该文件也可以使用 JSON 格式进行配置:
[
{
"targets": [ "<host>", ... ],
"labels": {
"<labelname>": "<labelvalue>", ...
}
},
...
]
如果是 YAML 文件则格式为:
- targets:
[ - '<host>' ]
labels:
[ <labelname>: <labelvalue> ... ]
2、配置文件服务发现
用于发现的目标文件创建完成后,要让 Prometheus 能够从上面的 targets.yml 文件中自动读取抓取目标,需要在 prometheus.yml 配置文件中的 scrape_configs 部分添加如下所示的抓取配置:
- job_name: 'file-sd-demo'
file_sd_configs:
- files:
- 'targets.yml'
重新 reload 或者重启下 Prometheus 让其重新读取配置文件信息,然后同样前往 Prometheus UI 的 targets 页面下面查看是否有上面定义的抓取目标。
然后我们可以尝试改变 targets.yml 的内容,比如为第三个实例增加一个 role: sd 的标签,不用重新加载 Prometheus 配置,Prometheus 将 watch 该文件,并自动接收任何变化。
**注意:**当在生产环境 Prometheus 服务器中改变 file_sd 目标文件时,确保改变是原子的,以避免重新加载出现错误,最好的方法是在一个单独的位置创建更新的文件,然后将其重命名为目标文件名(使用 mv 命令或 rename() 系统调用)。
这样我们就完成了基于文件的通用服务发现机制,可以让我们动态地改变 Prometheus 的监控目标,而不需要重新启动或重新加载 Prometheus 服务。当然除了基于 Consul 和文件的服务发现之外,更多的时候我们会在 Kubernetes 环境下面使用 Prometheus,由于这部分内容比较独立,后续我们再进行单独讲解。