title: Prometheus的服务发现机制 #标题tags: Prometheus服务发现 #标签
date: 2020-09-21
categories: 监控 # 分类

prometheus默认是采用pull方式拉取监控数据的,也就是定时去目标主机上抓取metrics数据,每一个被抓取的目标需要暴露一个HTTP接口,prometheus通过这个暴露的接口就可以获取到相应的指标数据,这种方式需要由目标服务决定采集的目标有哪些,通过配置在scrape_configs中的各种job来实现,无法动态感知新服务,如果后面增加了节点或者组件信息,就得手动修promrtheus配置,并重启 promethues,很不方便,所以出现了动态服务发现,动态服务发现能够自动发现集群中的新端点,并加入到配置中,通过服务发现,Prometheus能查询到需要监控的Target列表,然后轮询这些Target获取监控数据。

prometheus获取数据源target的方式有多种,如静态配置和服务发现配置,prometheus支持多种服务发现,在prometheus中的服务发现主要分为以下几种:

  • static_configs:静态服务发现
  • kubernetes_sd_configs: 基于Kubernetes的服务发现
  • consul_sd_configs: Consul 服务发现
  • dns_sd_configs: DNS 服务发现
  • file_sd_configs: 文件服务发现
  • promethues的静态静态服务发现static_configs:每当有一个新的目标实例需要监控,都需要手动配置目标target。
  • promethues的consul服务发现consul_sd_configs:Prometheus 一直监视consul服务,当发现在consul中注册的服务有变化,prometheus就会自动监控到所有注册到consul中的目标资源。
  • promethues的k8s服务发现kubernetes_sd_configs:Prometheus与Kubernetes的API进行交互,动态的发现Kubernetes中部署的所有可监控的目标资源。

基于K8s的服务发现

参考:

Kubernetes sd配置允许从Kubernetes的 REST API 检索抓取目标, 并始终与集群状态保持同步。

role可以将以下类型之一配置为发现目标:

node

该node角色为每个群集节点发现一个目标,其地址默认为Kubelet的HTTP端口。目标地址默认为的地址类型顺序Kubernetes节点对象的第一个现有地址NodeInternalIP,NodeExternalIP, NodeLegacyHostIP,和NodeHostName。

可用的元标签:

  • __meta_kubernetes_node_name:节点对象的名称。
  • _meta_kubernetes_node_label:节点对象中的每个标签。
  • _meta_kubernetes_node_labelpresent:true对于节点对象中的每个标签。
  • _meta_kubernetes_node_annotation:来自节点对象的每个注释。
  • _meta_kubernetes_node_annotationpresent:true用于节点对象的每个注释。
  • _meta_kubernetes_node_address:每个节点地址类型的第一个地址(如果存在)。
    此外,该instance节点的标签将设置为从API服务器检索到的节点名称。

service
该service角色发现每一个服务端口为每个服务的目标。通常,这对于监视服务的黑盒很有用。该地址将设置为服务的Kubernetes DNS名称以及相应的服务端口。

可用的元标签:

  • __meta_kubernetes_namespace:服务对象的名称空间。
  • _meta_kubernetes_service_annotation:服务对象的每个注释。
  • _meta_kubernetes_service_annotationpresent:对于服务对象的每个注释为“ true”。
  • __meta_kubernetes_service_cluster_ip:服务的群集IP地址。(不适用于“外部名称”类型的服务)
  • __meta_kubernetes_service_external_name:服务的DNS名称。(适用于外部名称类型的服务)
  • _meta_kubernetes_service_label:服务对象中的每个标签。
  • _meta_kubernetes_service_labelpresent:true用于服务对象的每个标签。
  • __meta_kubernetes_service_name:服务对象的名称。
  • __meta_kubernetes_service_port_name:目标服务端口的名称。
  • __meta_kubernetes_service_port_protocol:目标服务端口的协议。
  • __meta_kubernetes_service_type:服务的类型。

pod

该pod角色发现所有吊舱并将其容器公开为目标。对于容器的每个声明的端口,将生成一个目标。如果容器没有指定的端口,则会为每个容器创建无端口目标,以通过重新标记手动添加端口。

可用的元标签:

  • __meta_kubernetes_namespace:pod对象的名称空间。
  • __meta_kubernetes_pod_name:pod对象的名称。
  • __meta_kubernetes_pod_ip:pod对象的pod IP。
  • _meta_kubernetes_pod_label:来自pod对象的每个标签。
  • _meta_kubernetes_pod_labelpresent:true用于pod对象中的每个标签。
  • _meta_kubernetes_pod_annotation:来自pod对象的每个注释。
  • _meta_kubernetes_pod_annotationpresent:true用于pod对象的每个注释。
  • __meta_kubernetes_pod_container_init:true如果容器是InitContainer
  • __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:设置true或false吊舱的准备状态。
  • __meta_kubernetes_pod_phase:在生命周期设置为Pending,Running,Succeeded,Failed或Unknown 。
  • __meta_kubernetes_pod_node_name:将Pod调度到的节点的名称。
  • __meta_kubernetes_pod_host_ip:pod对象的当前主机IP。
  • __meta_kubernetes_pod_uid:pod对象的UID。
  • __meta_kubernetes_pod_controller_kind:pod控制器的对象种类。
  • __meta_kubernetes_pod_controller_name:pod控制器的名称。

endpoints

该endpoints角色从列出的服务端点发现目标。对于每个端点地址,每个端口都发现一个目标。如果端点由Pod支持,则该Pod的所有其他容器端口(未绑定到端点端口)也将作为目标。

可用的元标签:

  • __meta_kubernetes_namespace:端点对象的名称空间。
  • __meta_kubernetes_endpoints_name:端点对象的名称。
    对于直接从端点列表中发现的所有目标(未从基础容器中另外推断出的那些目标),将附加以下标签:

    • __meta_kubernetes_endpoint_hostname:端点的主机名。
    • __meta_kubernetes_endpoint_node_name:托管端点的节点的名称。
    • __meta_kubernetes_endpoint_ready:设置为true或false为端点的就绪状态。
    • __meta_kubernetes_endpoint_port_name:端点端口的名称。
    • __meta_kubernetes_endpoint_port_protocol:端点端口的协议。
    • __meta_kubernetes_endpoint_address_target_kind:端点地址目标的种类。
    • __meta_kubernetes_endpoint_address_target_name:端点地址目标的名称。
  • 如果端点属于服务,role: service则会附加发现的所有标签。

  • 对于由Pod支持的所有目标,role: pod将附加发现的所有标签。

ingress
该ingress角色发现了一个目标,为每个进入的每个路径。这通常对黑盒监视入口很有用。该地址将设置为入口规范中指定的主机。

可用的元标签:

  • __meta_kubernetes_namespace:入口对象的名称空间。
  • __meta_kubernetes_ingress_name:入口对象的名称。
  • _meta_kubernetes_ingress_label:来自入口对象的每个标签。
  • _meta_kubernetes_ingress_labelpresent:true用于来自入口对象的每个标签。
  • _meta_kubernetes_ingress_annotation:来自入口对象的每个注释。
  • _meta_kubernetes_ingress_annotationpresent:true用于来自入口对象的每个注释。
  • __meta_kubernetes_ingress_scheme:https如果设置了TLS配置,则为入口的协议方案。默认为http。
  • __meta_kubernetes_ingress_path:来自入口规范的路径。默认为/。

k8s服务发现之endpoints模式

在上篇博文中,Prometheus的配置文件如下:

监控(2):Prometheus的服务发现机制 - 图1

  1. - job_name: 'kubernetes-apiserver'
  2. kubernetes_sd_configs:
  3. - role: endpoints # 此处定义了服务发现模式为 endpoints模式
  4. scheme: https
  5. tls_config:
  6. ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  7. bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  8. relabel_configs:
  9. - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
  10. action: keep
  11. regex: default;kubernetes;https

在上面的配置中,主要就是为了Prometheus自动监控api-server这个组件,Prometheus监控到的组件信息如下:

监控(2):Prometheus的服务发现机制 - 图2

在上图中可以看到,很多Prometheus默认采集到的标签,那么我们在Prometheus的配置文件中指定了relabel_configs配置,如下:

  1. relabel_configs:
  2. - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
  3. action: keep
  4. regex: default;kubernetes;https

关于relabel_configs可选配置,我在这里都介绍下,如下:

  • source_labels: 表示源标签(没有经过relabel处理之前的标签名字),上述指定的源标签,都是我们在Prometheus的UI界面的红框中可以看到的(我上一个截图中标识出来的红框),prometheus加载target成功之后,在Target实例中,都包含一些Metadata标签信息,默认的标签有:

    • address:以: 格式显示目标targets的地址
    • scheme:采集的目标服务地址的Scheme形式,HTTP或者HTTPS
    • metrics_path:采集的目标服务的访问路径
  • action: action定义了relabel的动作,action支持多种,如下:

    • replace: 替换标签值,根据regex正则匹配到源标签的值,并把匹配的值写入到目的标签中。
    • keep: 满足regex正则条件的实例进行采集,把source_labels中没有匹配到regex正则内容的Target实例丢掉。
    • drop: 满足regex正则条件的实例不采集,把source_labels中匹配到regex正则内容的Target实例丢掉。
    • labeldrop: 对抓取到的符合过滤规则的target标签进行删除
    • labelkeep: 对抓取到的符合过滤规则的target标签进行保留
  • target_labels: 通过action处理之后的标签名字。

  • regex: 正则表达式,匹配源标签(在上述的配置中,regex: default;kubernetes;https表示meta_kubernetes_namespace的值为default的,meta_kubernetes_service_name的值为kubernetes的,并且__meta_kubernetes_endpoint_port_name值为https的,就进行keep动作(对满足regex正则条件的实例进行采集))
  • replacement:replacement指定的替换后的标签(target_label)对应的数值。
  • labelmap: 会根据regex的定义去匹配Target实例所有标签的名称,并且以匹配到的内容为新的标签名称,其值作为新标签的值。

那么,在上面我们知道了各项配置的意思,现在试试,如果Prometheus中没有上面relabel_configs那些配置,会采集到什么样的数据呢?修改配置文件如下:

  1. - job_name: 'kubernetes-apiserver'
  2. kubernetes_sd_configs:
  3. - role: endpoints
  4. scheme: https
  5. tls_config:
  6. ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  7. bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

Prometheus数据采集页面如下:

监控(2):Prometheus的服务发现机制 - 图3

可以看到,如果没有配置relabel_configs对标签进行过滤,那么会采集到很多其他信息,在上图中有coredns的及calico等组件的监控信息,由于那些目标并不没有相应的/metrics路径,故状态都为down。这就是relabel_configs的魅力。

k8s之node-exporter服务发现
  1. # 摘自上篇博文中的配置
  2. - job_name: 'kubernetes-node'
  3. kubernetes_sd_configs:
  4. - role: node
  5. relabel_configs:
  6. - source_labels: [__address__]
  7. regex: '(.*):10250'
  8. replacement: '${1}:9100'
  9. target_label: __address__
  10. action: replace
  11. - action: labelmap
  12. regex: __meta_kubernetes_node_label_(.+)

上述就是自动发现node节点的配置,通过指定Kubernetes_sd_config的模式为node,prometheus就会自动从Kubernetes中发现所有的node节点并作为当前job监控的目标实例,发现的节点/metrics接口是默认的kubelet的HTTP接口,但是由于metrics监听的端口是9100而并不是默认的10250端口,所以这里就需要使用Prometheus提供的relabel_configs中的replace能力了。

relabel可以在Prometheus采集数据之前,通过Target实例的Metadata信息,动态重新写入Label的值,这里使用address标签替换10250端口为9100,才可以正确的采集到node信息。

还添加了一个action为labelmap,正则表达式是__meta_kubernetes_node(.+)的配置,这里的意思就是表达式中匹配的数据也添加到指标数据的Label标签中去。此配置采集的就是通过kubectl get nodes --show-labels命令采集到的标签。

通过上面的配置,我们可以使Prometheus采集到集群中运行node-export程序的所有节点信息,如下:

监控(2):Prometheus的服务发现机制 - 图4

为了展现我们配置relabel_configs的作用,现在将去掉端口替换的配置,修改后的配置如下:

  1. - job_name: 'kubernetes-node'
  2. kubernetes_sd_configs:
  3. - role: node
  4. relabel_configs:
  5. - action: labelmap
  6. regex: __meta_kubernetes_node_label_(.+)

此时,我们的Prometheus将无法采集到node节点的信息,因为使用了默认的10250端口去采集节点信息,如下:

监控(2):Prometheus的服务发现机制 - 图5

现在来确认第二个action的配置作用,修改配置文件如下:

  1. - job_name: 'kubernetes-node'
  2. kubernetes_sd_configs:
  3. - role: node
  4. relabel_configs:
  5. - source_labels: [__address__]
  6. regex: '(.*):10250'
  7. replacement: '${1}:9100'
  8. target_label: __address__
  9. action: replace

此时,可以看到如下,可以正常采集到数据,但是标签少了很多东西(鼠标悬浮到标签上显示的是重写标签之前的标签):

监控(2):Prometheus的服务发现机制 - 图6

由此可以看出,上面配置中的action: labelmap,就是通过正则将匹配到的元标签中的数据给删除,并且进行重写,上述配置的正则是将元标签中的__meta_kubernetes_node_label_进行了删除,保留了后面的信息作为标签名。

k8s之自动发现cadvisor采集数据
  1. - job_name: 'kubernetes-node-cadvisor'
  2. kubernetes_sd_configs:
  3. - role: node
  4. scheme: https
  5. tls_config:
  6. ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  7. bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  8. relabel_configs:
  9. - action: labelmap
  10. regex: __meta_kubernetes_node_label_(.+)
  11. - target_label: __address__
  12. replacement: kubernetes.default.svc:443
  13. - source_labels: [__meta_kubernetes_node_name]
  14. regex: (.+)
  15. target_label: __metrics_path__
  16. replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

tls_config配置的证书地址是每个Pod连接apiserver所使用的地址,基本上写死了,证书是我们Pod启动的时候kubelet给pod注入的一个证书,所有的pod启动的时候都会有一个ca证书注入进来,如要想要访问apiserver的信息,还需要配置一个token_file。

relabel_configs: 用新的前缀代替原label name前缀,没有replacement的话功能就是去掉label name前缀。

例如: 以下两句的功能就是将__meta_kubernetes_node_label_kubernetes_io_hostname变为kubernetes_io_hostname

  1. - action: labelmap
  2. regex: __meta_kubernetes_node_label_(.+)

replacement 中的值将会覆盖target_label中指定的label name的值,如下,address的值会被替换为kubernetes.default.svc:443:

  1. - target_label: __address__
  2. replacement: kubernetes.default.svc:443
  1. # 获取__meta_kubernetes_node_name的值
  2. - source_labels: [__meta_kubernetes_node_name]
  3. # 匹配一个或多个任意字符,将上述source_labels的值生成变量
  4. regex: (.+)
  5. # replacement中的值将会覆盖target_label中指定的label name的值
  6. # 即__metrics_path__的值会被替换为/api/v1/nodes/${1}/proxy/metrics
  7. # 其中${1}的值会被替换为__meta_kubernetes_node_name的值。
  8. target_label: __metrics_path__
  9. replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor