一、Prometheus为何要进行服务发现
Prometheus Server的数据抓取模型为Pull,因而,它必须事先知道各Target的位置,然后才能从相应的Exporter或Instrumentation中抓取数据。对于小型的系统环境而言,通过static_configs指定各Target即可解决问题,每个Target用一个网络端点(ip:port)进行标识;但对于中大型系统环境或具有较强动态性的云计算环境来说,静态配置显然难以使用。因此,Prometheus为此专门设计了一组服务发现机制,以便于能够基于服务注册中心(服务总线)自动发现、检测、分类可被监控的各Target,以及更新发生了变动的Target。
二、指标抓取的生命周期
在每个scrape_interval期间,Prometheus都会检查执行的作业(Job),这些作业会根据Job上指定的发现配置生成target列表,此为服务发现过程。具体可描述为:
(1)服务发现会返回一个Target列表,其中包含一组称为元数据的标签,这些标签都以”__meta_”为前缀;
(2)服务发现还会根据目标配置来设置其它标签,这些标签带有”__”前缀和后缀,包括”__scheme__”、”__address__”和”__metrics_path__”,分别保存target支持使用的协议(http或https,默认使用http)、target的地址及指标的URI路径(默认为/metrics);
(3)若URI路径中存在任何参数,则它们的前缀会设置为”__param_”;
(4)这些目标列表和标签会返回给Prometheus,其中一些标签也可以在配置中被覆盖。
下图介绍了Prometheus进行指标抓取的简单生命周期
prometheus的relabeling(标签重写)功能,它允许用户重写这些标签或根据标签做一些过滤操作。目前支持的relabel配置主要有以下4种,它的应用范围和生效时间不一样:
- relabel_configs:在对target进行数据采集之前,可以使用relabel_configs添加、修改或删除一些标签,也可以用来配置只采集特定目标或过滤目标,针对的是target,监控目标(较为常用)。
- metric_relabel_configs:在对target采集数据之后,数据写入TSDB之前,可以使用metric_relabel_configs做重新标记和过滤,也可删除指标或指标中的标签。针对的是metric,指标。
- alert_relabel_configs:在被发送到alertmanager之前,对标签进行处理,针对的是alert。
- write_relabel_configs:写入远端存储之前进行标签处理。
对于发现的每个target,Prometheus默认会执行如下操作。
- job的标签设定为其所属的job_name的值
- __address__标签的值为该target的套接字地址:”<host>:<port>”
- instance标签的值为__address__的值
- __scheme__标签的值为抓取该target上指标时使用的协议(http或https)
- __metrics_path__标签的值为抓取该target上的指标时使用的URI路径,默认为/metrics
- __param_<name>标签的值为传递的URL参数中第一个名称为<name>的参数的值
重新标记期间,还可以使用该target上以“__meta_”开头的元标签,不同的服务发现机制为其target添加的元标签会有所不同。
重新标记完成后,该target上以“__”开头的所有标签都会被移除。
注意:每个target都有两个用于标识身份的标签:instance和job。
三、relabel_configs
相关参数介绍如下:
#源标签从现有标签中选择值。它们的内容是串联的
#使用配置的分隔符并与配置的正则表达式匹配
#用于替换、保留和丢弃操作。
[ source_labels: '[' <labelname> [, ...] ']' ]
#位于连接的源标签值之间的分隔符。
[ separator: <string> | default = ; ]
#在替换操作中将结果值写入的标签。
#对于替换操作,它是强制性的。Regex捕获组可用。
[ target_label: <labelname> ]
#与提取值匹配的正则表达式
[ regex: <regex> | default = (.*) ]
#获取源标签值的哈希值的模数
[ modulus: <int> ]
#正则表达式匹配时执行正则表达式替换的替换值(即要替换成啥)。正则表达式捕获组可用。
[ replacement: <string> | default = $1 ]
#基于正则表达式匹配要执行的操作
[ action: <relabel_action> | default = replace ]
<relabel_action>字段用于定义重新标记的行为,其可用取值如下。
(1)替换标签值
A. replace
首先将source_labels中指定的各标签的值进行串连,而后将regex字段中的正则表达式对源标签值进行匹配判定,若匹配,则将target_label字段中指定的标签的值替换为replacement字段中保存的值。
replacement可按需引用保存regex中的某个“分组模式”匹配到的值;默认保存整个regex匹配到的内容。在进行值替换时,replacement字段中指定标签的值也支持以分组格式进行引用。
B. hashmod
将target_label的值设置为一个hash值,该hash值由modules字段指定的hash模块对source_labels上各标签的串连值进行hash计算生成。
(2)删除指标:该处的每个指标名称对应一个target
A. keep:regex不能匹配到target上的source_labels上的各标签的串连值时,则删除该target,否则(能匹配串连值)保留该target。
B. drop:regex能够匹配到target上的source_labels上的各标签的串连值时,则删除该target,否则(不能匹配串连值)保留该target。
(3)创建或删除标签
A. labelmap:将regex对所有的标签名(多指源标签)进行匹配判定,而后将匹配到的标签的值赋给replacement字段指定的标签名之上;通常用于取出匹配的标签名的一部分生成新标签
B. labeldrop:将regex对所有的标签名(多指源标签)进行匹配判定,能够匹配到的标签将从该target的标签集中删除
C. labelkeep:将regex对所有的标签名(多指源标签)进行匹配判定,不能匹配到的标签将从该target的标签集中删除
四、基于文件的服务发现
此方式不依赖于任何平台或第三方服务,简单通用。Prometheus Server定期从文件中加载Target信息,文件可使用json或yaml格式,包含定义的Target列表以及可选的标签信息。这些文件也可由其它系统生成(eg:Ansible)。
发现Target的配置,定义在配置文件的job之中。
新建一个/usr/local/Prometheus/file_sd/node_exporter.yml,添加如下内容:
- targets:
- 192.168.131.11:9100
labels:
app: node_exporter
job: node
在Prometheus配置文件添加如下内容:
- job_name: node_exporter
file_sd_configs:
- files: #指定保存targets文件的位置,可以指定多个
- file_sd/*.yml #文件加载支持通配符
refresh_interval: 10s #每隔多长时间从指定的文件中加载一次targets
执行curl -XPOST http://192.168.131.11:9090/-/reload命令去热加载。此时查看Prometheus Web UI的Targets,发现在新添加的Target中的app: node_exporter和job: node已经添加进来了。
此外,将鼠标悬浮在端点对应的Labels时还能看到多了一个元标签__meta_filepath。此标签在静态配置时是没有的。当然,这些标签信息也可以在Prometheus Web UI的Service Discovery中也能看到。
五、基于DNS的服务发现
基于DNS的服务发现针对一组DNS域名进行定期查询,以发现待监控的目标。此发现机制依赖于A、AAAA和SRV资源记录,且仅支持该类方法,尚不支持RFC6763中的高级DNS发现方式。
六、基于Consul的服务发现
6.1 Consul简介
Consul是一款基于golang开发的开源工具,主要面向分布式、服务化的系统提供服务注册、服务发现和配置管理的功能,提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。
6.2 部署Consul
下载地址:https://developer.hashicorp.com/consul/downloads?product_intent=consul
wget https://releases.hashicorp.com/consul/1.16.1/consul_1.16.1_linux_386.zip
unzip consul_1.16.1_linux_386.zip
mv consul /usr/local/bin
#启动开发者模式。先创建数据存储目录和配置文件目录,便于后续使用
mkdir -p /consul/data /etc/consul
nohup consul agent -dev -ui -data-dir=/consul/data -config-dir=/etc/consul -client=0.0.0.0 &
访问http://Consul IP:8500,就能看到Consul自带的Web UI界面,consul本身也被注册进来。
6.3 在Consul上注册Service
#在配置目录下操作
vim /etc/consul/nodes.json
{
"services": [{
"id": "node_exporter_node1",
"name": "node1",
"address": "192.168.131.11",
"port": 9100,
"tags": ["nodes"],
"checks": [{
"http": "http://192.168.131.11:9100/metrics",
"interval": "10s"
}]
},
{
"id": "node_exporter_node2",
"name": "node2",
"address": "192.168.131.12",
"port": 9100,
"tags": ["nodes"],
"checks": [{
"http": "http://192.168.131.12:9100/metrics",
"interval": "10s"
}]
}]
}
之后运行consul reload命令,让consul重新加载配置信息。也可以直接基于HTTP API提交注册的服务信息。
curl -X PUT --data@nodes.json http://192.168.131.11:8500/v1/agent/service/register
要想注销Service,执行consul service deregister命令,或通过deregister API完成。
6.4 为Consul设置systemd开机自启
vim /usr/lib/systemd/system/consul.service
[Unit]
Description="HashiCorp Consul - A service mesh solution"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
[Service]
EnvironmentFile=-/etc/consul.d/consul.env
ExecStart=/usr/local/bin/consul agent -dev -bootstrap \
-config-dir /etc/consul \
-data-dir /consul/data \
-ui \
-log-level INFO \
-bind 192.168.131.11 \
-client 0.0.0.0
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGTERM
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
systemctl enable --now consul
6.5 Prometheus定义consul_sd_configs
在Prometheus配置文件添加如下内容:
- job_name: "node_exporter"
consul_sd_configs:
- server: "192.168.131.11:8500"
tags:
- "nodes"
refresh_interval: 10s
执行完热加载命令后,同样在Targets也能看到发现的目标节点。此时将鼠标悬浮在端点对应的Labels时,就会发现有许多以”_meta_consul”为前缀的元标签。
七、基于Kubernetes API的服务发现
基于Kubernetes API的服务发现机制,支持将API Server中的Node、Service、Endpoint、Pod和Ingress等资源类型下相应的各资源对象视为target,并持续监视相关资源的变动。
- Node、Service、Endpoint、Pod和Ingress资源分别由各自的发现机制进行定义
- 负责发现每种资源对象的组件,在Prometheus中称为一个”role”
- 同时支持在集群上基于DaemonSet控制器部署node-exporter后发现各节点
7.1 Node
Node角色将Kubernetes集群内的每个节点均视为一个target,同时监听Kubelet的HTTP端口(10250)。Node Role依次检索节点规范上的NodeInternalIP、NodeExternalIP、NodeLegacyHostIP和NodeHostName,并将发现的第一个地址作为目标地址(__address__)。主要用于监控Kubernetes的Node节点的服务器相关的指标数据。
可用标签列举如下:
- __meta_kubernetes_node_name:Node节点的名称
- __meta_kubernetes_node_label:Kubernetes中Node节点的标签。<labelname>代表标签名称
- __meta_kubernetes_node_labelpresent:标签存在则为true。<labelname>代表标签名称
- __meta_kubernetes_node_annotation:Kubernetes中Node节点的注解。<annotationname>代表注解名称
- __meta_kubernetes_node_annotationpresent:注解存在则为true。<annotationname>代表注解名称
- __meta_kubernetes_node_address<address_type>:不同类型的Node节点地址。例如: __meta_kubernetes_node_address_Hostname="test-k8s-node1;__meta_kubernetes_node_address_InternalIP="10.0.0.11"
- instance:从apiserver获取到的节点名称
7.2 Pod
Pod角色可以发现Kubernetes集群上的所有pod并将其中的pod ip作为target,它会将Pod上声明的每个端口都视作一个target。如果容器没有指定的端口,则会为每个容器创建一个无端口target,以便通过relabel手动添加端口。
可用标签列举如下:
- __meta_kubernetes_namespace:pod所在的命名空间
- __meta_kubernetes_pod_name:pod的名称
- __meta_kubernetes_pod_ip:pod的ip
- __meta_kubernetes_pod_label_<labelname>:pod的标签
- __meta_kubernetes_pod_labelpresent_<labelname>:标签存在则为true
- __meta_kubernetes_pod_annotation_<annotationname>:pod的注解
- __meta_kubernetes_pod_annotationpresent_<annotationname>:注解存在则为true
- __meta_kubernetes_pod_container_init:如果容器是InitContainer,则为true
- __meta_kubernetes_pod_container_name:容器的名称
- __meta_kubernetes_pod_container_port_name:容器的端口名称
- __meta_kubernetes_pod_container_port_number:容器的端口号
- __meta_kubernetes_pod_container_port_protocol:容器的端口协议
- __meta_kubernetes_pod_ready:pod的就绪状态,true或false
- __meta_kubernetes_pod_phase:pod的生命周期状态,Pending, Running, Succeeded, Failed or Unknown
- __meta_kubernetes_pod_node_name:Pod所在Node节点的名称
- __meta_kubernetes_pod_host_ip:Pod所在Node节点的ip
- __meta_kubernetes_pod_uid:Pod的uid
- __meta_kubernetes_pod_controller_kind:Pod控制器的类型,ReplicaSet,DaemonSet,Job,StatefulSet…
- __meta_kubernetes_pod_controller_name:Pod控制器的名称
7.3 Service
Service
角色可以发现每个Service的ip和port,将其作为target。这对于黑盒监控(blackbox)很有用。即一个Service访问到哪个pod,就把哪个pod的数据传上来。使用的场景很少。只是看Service对应业务是否健康的时候可以使用。
可用标签列举如下:
- __meta_kubernetes_namespace:Service所在的命名空间
- __meta_kubernetes_service_annotation_<annotationname>:Kubernetes中Service的注解
- __meta_kubernetes_service_annotationpresent_<annotationname>:注解存在则为true
- __meta_kubernetes_service_cluster_ip:Kubernetes中Service的ClusterIP
- __meta_kubernetes_service_external_name:Kubernetes中Service的external_name
- __meta_kubernetes_service_label_<labelname>:Kubernetes中Service的标签
- __meta_kubernetes_service_labelpresent_<labelname>:标签存在则为true
- __meta_kubernetes_service_name:Kuberentes中Service的名称
- __meta_kubernetes_service_port_name:Kubernetes中Service的端口
- __meta_kubernetes_service_port_protocol:Kubernetes中Service的端口协议
- __meta_kubernetes_service_type:Kubernetes中Service的类型
7.4 Endpoint
Endpoint role从各Endpoint资源中发现目标。如果ep是属于service的话,则会附加Service角色的所有标签。如果ep的后端节点是pod,则会附加pod角色的所有标签。
可用标签列举如下:
(1)__meta_kubernetes_namespace:ep对象所在的命名空间
(2)__meta_kubernetes_endpoints_name:ep的名称
(3)直接从ep对象的列表中获取的所有target,下面的标签将会被附加上
①__meta_kubernetes_endpoint_hostname:ep的主机名
②__meta_kubernetes_endpoint_node_name:ep所在的node节点名
③__meta_kubernetes_endpoint_ready:ep的就绪状态,true或false
④__meta_kubernetes_endpoint_port_name:ep的端口名称
⑤__meta_kubernetes_endpoint_port_protocol:ep的端口协议
⑥__meta_kubernetes_endpoint_address_target_kind:ep对象的目标类型,比如Pod
⑦__meta_kubernetes_endpoint_address_target_name:ep对象的目标名称,比如pod名称
7.5 Ingress
ingress角色负责从API Server中发现ingress资源,它将ingress资源上的每个路径视为一个target。这通常对黑盒监控很有用。该地址将设置为ingress资源中指定的host字段的值。
可用标签列举如下:
- __meta_kubernetes_namespace:ingress所在的命名空间
- __meta_kubernetes_ingress_name:ingress的名称
- __meta_kubernetes_ingress_label_<labelname>:ingress的标签
- __meta_kubernetes_ingress_labelpresent_<labelname>:标签存在则为true
- __meta_kubernetes_ingress_annotation_<annotationname>:ingress的注解
- __meta_kubernetes_ingress_annotationpresent_<annotationname>:注解存在则为true
- __meta_kubernetes_ingress_scheme:ingress的协议,如果设置了tls则是https。默认http
- __meta_kubernetes_ingress_path:ingress中指定的路径。默认为/