一、prometheus 的服务发现机制
prometheus 默认是采用 pull 方式拉取监控数据的, 也就是定时去目标主机上抓取 metrics 数据, 每一个被抓取的目标需要暴露一个 HTTP 接口, prometheus通过这个暴露的接口就可以获取到相应的指标数据,
这种方式需要由目标服务决定采集的目标有哪些, 通过配置在 scrape_configs 中的各种 job 来实现, 无法动态感知新服务, 如果后面增加了节点或者组件信息, 就得手动修 promrtheus配置,
并重启 promethues, 很不方便, 所以出现了动态服务发现, 动态服务发现能够自动发现集群中的新端点, 并加入到配置中, 通过服务发现, Prometheus能查询到需要监控的 Target 列表, 然后轮询这些 Target 获取监控数据。
prometheus 获取数据源 target 的方式有多种,如静态配置和动态服务发现配置,prometheus 目前支持的服务发现有很多种, 常用的主要分为以下几种:
1.kubernetes_sd_configs: #基于 Kubernetes API 实现的服务发现, 让 prometheus 动态发现 kubernetes 中被监控的目标
2.static_configs: #静态服务发现, 基于 prometheus 配置文件指定的监控目标,每当有一个新的目标实例需要监控, 都需要手动修改配置文件配置目标 target。
3.dns_sd_configs: #DNS 服务发现监控目标
4.consul_sd_configs: #Consul 服务发现, 基于 consul 服务动态发现监控目标
5.file_sd_configs: #基于指定的文件实现服务发现, 基于指定的文件发现监控目标,相比较于静态服务发现,使用文件服务发现可以不重启prometheus服务
参考文档:https://prometheus.io/docs/prometheus/latest/configuration/configuration/ #所有 *_sd_config> 为当前支持的自动发现的配置
二、prometheus 标签修改(relabeling)
promethues 的 relabeling(重新修改标签) 功能很强大, 它能够在抓取到目标实例之前把目标实例的元数据标签动态重新修改, 动态添加或者覆盖标签
prometheus 动态发现目标(targer)之后, 在被发现的 target 实例中, 都包含一些原始的Metadata 标签信息, 默认的标签有:
__address__: 以<host>:<port> 格式显示目标 targets 的地址
__scheme__: 采集的目标服务地址的 Scheme 形式, HTTP 或者 HTTPS
__metrics_path__: 采集的目标服务的访问路径
1.label重新标记
为了更好的识别监控指标,便于后期调用数据绘图、 告警等需求, prometheus 支持对发现的目标进行 label 修改, 在两个阶段可以重新标记:
relabel_configs : 在对 target 进行数据采集之前(比如在采集数据之前重新定义标签信息, 如目的 IP、目的端口等信息) , 可以使用 relabel_configs 添加、 修改或删除一些标签、 也可以只采集特定目标或过滤目标。
metric_relabel_configs: 在对 target 进行数据采集之后, 即如果是已经抓取到指标数据时, 可以使用metric_relabel_configs 做最后的重新标记和过滤。流程如下
如上一篇文章总prometheus kubernetes_sd_configs服务自动发现中对api-server抓取的配置
- job_name: 'kubernetes-apiserver' #
kubernetes_sd_configs: #基于 kubernetes_sd_configs 实现服务发现
- role: endpoints #发现 endpoints,还有 node svc pod ingress等其他role
scheme: https #当前 jod 使用的发现协议
tls_config: #证书配置
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt #容器里的证书路径,默认内置存在 为集群ca证书的公钥
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token #容器里的 token 路径,默认内置存在
relabel_configs: #重新 re 修改标签 label 配置 configs
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] #源标签,即对哪些标签进行操作,不同的发现机制源标签也不相同,具体参考对应的发现机制官方文档
action: keep #保留source_labels中标签,其他过滤,action 定义了 relabel 的具体动作, action 支持多种
regex: default;kubernetes;https #与source_labels中对应,分别为名称空间 svc名称 svc中port的名称,注意此处是名称不是协议,协议在scheme字段配置,此处含义为发现 default 命名空间的 kubernetes 服务并且是 https 协议
在数据收集后,在web页面可以看到所有修改之前的label
2.label 详解
source_labels: 源标签, 没有经过 relabel 处理之前的标签名字
target_label: 通过 action 处理之后的新的标签名字
regex: 给定的值或正则表达式匹配, 匹配源标签
replacement: 通过分组替换后标签(target_label) 对应的值
如以下示例:
relabel_configs: #重写标签配置
- source_labels: [__address__]
regex: '(.*):10250' #10250为kubelet端口 但是我们的node-export部署的端口是9100,所以在抓取数据前需要修改数据采集的端口
replacement: '${1}:9100' #9100为node-exporterj监听的端口,此处表示将发现的地址包含10250端口的替换为9100,通过正则保留原IP并对该IP:端口进行数据抓取
target_label: __address__
action: replace #操作的类型为替换
3.action 详解
replace: 替换标签值, 根据 regex 正则匹配到源标签的值, 使用 replacement 来引用表达式匹配的分组
keep: 满足 regex 正则条件的实例进行采集, 把 source_labels 中没有匹配到 regex 正则内容的 Target实例丢掉, 即只采集匹配成功的实例。
drop: 满足 regex 正则条件的实例不采集,把 source_labels 中匹配到 regex 正则内容的 Target 实例丢掉,即只采集没有匹配到的实例。
hashmod: 使用 hashmod 计算 source_labels 的 Hash 值并进行对比, 基于自定义的模数取模, 以实现对目标进行分类、 重新赋值等功能如以下示例:
scrape_configs:
- job_name: ip_job
relabel_configs:
- source_labels: [__address__]
modulus: 4
target_label: __ip_hash
action: hashmod
- source_labels: [__ip_hash]
regex: ^1$
action: keep
labelkeep: 匹配 regex 所有标签名称,其它不匹配的标签都将从标签集中删除
labeldrop: 匹配 regex 所有标签名称,其它匹配的标签都将从标签集中删除
labelmap: 匹配 regex 所有标签名称,然后复制匹配标签的值进行分组, 通过 replacement 分组引用(${1},${2},…) 替代,如以下示例
- action: labelmap
regex: __meta_kubernetes_node_label_(.+) #匹配对应role的标签,此处为node的标签 即 kubectl get node --show-labels 分别将label的名称和值,如下所示
三、kubernetes_sd_configs服务自动发现
参考文档:https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config
Kubernetes 服务发现配置允许从Kubernetes的REST API接口检索并抓取目标,且始终与集群状态保持同步
1. 支持的发现目标类型
node
service
pod
endpoints
Endpointslice #对 endpoint 进行切片
ingress
2.监控 api-server 实现
1.查看api-server svc信息
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 42h
2.查看api-server svc后端endpoint信息
kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.10.89:6443 42h
3.prometheus配置自动方向api-server
- job_name: 'kubernetes-apiserver'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep #保留source_labels中标签,其他过滤
regex: default;kubernetes;https #与source_labels中对应,分别为名称空间 svc名称 svc中port的名称,注意此处是名称不是协议,协议在scheme字段配置.#含义为匹配 default 的 namespace, svc 名称是 kubernetes
并且协议是 https,匹配成功后进行保留,并且把 regex 作为 source_labels 相对应的值。即 labels 为 key、regex 为值。
abel 替换方式如下:
__meta_kubernetes_namespace=default,__meta_kubernetes_service_name=kubernetes,__meta_kubernetes_endpoint_port_name=https
最终, 匹配到 api-server 的地址: 192.168.10.89:6443,如下图:
3.api-server 指标数据
Apiserver 组件是 k8s 集群的入口, 所有请求都是从 apiserver 进来的, 所以对apiserver 指标做监控可以用来判断集群的健康状况
1.apiserver_request_total
apiserver_request_total 为请求各个服务的访问详细统计,如以下示例
#查询 apiserver 最近一分钟不同方法的请求数量统计
sum(rate(apiserver_request_total[1m])) by (resource,subresource,verb)
irate 和 rate 都会用于计算某个指标在一定时间间隔内的变化速率。 但是它们的计算方法有所不同: irate 取的是在指定时间范围内的最近两个数据点来算速率,而 rate 会取指定时间范围内所有数据点, 算出一组速率, 然后取平均值作为结果
所以官网文档说: irate 适合快速变化的计数器(counter) , 而 rate 适合缓慢变化的计数器(counter) 。
根据以上算法我们也可以理解, 对于快速变化的计数器, 如果使用 rate, 因为使用了平均值, 很容易把峰值削平。 除非我们把时间间隔设置得足够小, 就能够减弱这种效应。
#以下为rate和irate的对比,抓取5分支内状态码为2xx的请求
rate(apiserver_request_total{code=~"^(?:2..)$"}[5m])
irate(apiserver_request_total{code=~"^(?:2..)$"}[5m])
4.prometheus抓取注解
prometheus.io/scrape:表示是否需要prometheus采集Pod的监控数据,取值为true,如果需要被prometheus抓取必须配置。
prometheus.io/port:表示采集监控数据接口的端口。
prometheus.io/path:表示采集监控数据接口的URL,如不配置则默认为“/metrics“。
prometheus.io/scheme:表示采集的协议,值可以填写http或https。
如coredns的自动发现配置
我们可以看到实际的地址为coredns pod地址,但是端口却是9153,原因就是coredns的svc中配置了prometheus相关的注解
5.kubernetes_sd_configs服务自动发现常见配置
- job_name: 'kubernetes-service-endpoints' #job 名称
kubernetes_sd_configs: #k8s sd_configs 发现
- role: endpoints #角色, endpoints 发现
relabel_configs: #标签重写配置
#annotation_prometheus_io_scrape 的值为 true, 保留标签然后再向下执行,这样可以排除那些本身无法抓取的对象
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
#将__meta_kubernetes_service_annotation_prometheus_io_scheme 修改为__scheme__
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?) #正则匹配协议 http 或 https, 即其它协议不替换
#将 source_labels 替换为 target_label
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+) #路径为 1 到任意长度
#地址发现及标签重写
- source_labels: [__address__,__meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__ #将上面的地址和端口进行组合
regex: ([^:]+)(?::\d+)?;(\d+) #匹配V4或者V6的IP和端口并赋值给__address__
replacement: $1:$2 #格式为地址:端口
#发现新的 lable 并用新的 service name 作为 label、 将发现的值依然新的 label 的值
- action: labelmap
regex: __meta_kubernetes_service_label_(.+) #通过正则匹配 service name
#将__meta_kubernetes_namespace 替换为 kubernetes_namespace
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
#将__meta_kubernetes_service_name 替换为 kubernetes_name
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
6.kube-dns 的服务发现配置
- job_name: 'kubernetes-service-endpoints'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] #直接包含在所有的svc中,如果需要但你的抓取kube-dns可以再过滤kube-dns的端口
action: keep
regex: true
当然也可以单独设置抓取kube-dns
- job_name: coredns
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels:[__meta_kubernetes_service_label_k8s_app]
regex: kube-dns
action: keep
- source_labels: [__meta_kubernetes_pod_ip]
regex: (.+)
target_label: __address__
replacement: ${1}:9153
- source_labels: [__meta_kubernetes_endpoints_name]
action: replace
target_label: endpoint
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: pod
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: service
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: namespace
效果如下
7.node 节点发现及指标
- job_name: 'kubernetes-node' #k8s自动发现
kubernetes_sd_configs:
- role: node
relabel_configs: #重写标签配置
- source_labels: [__address__]
regex: '(.*):10250' #10250为kubelet端口 但是我们的node-export部署的端口是9100,所以在抓取数据前需要修改数据采集的端口
replacement: '${1}:9100' #9100为node-exporterj监听的端口,此处表示将发现的地址包含10250端口的替换为9100,通过正则保留原IP并对该IP:端口进行数据抓取 如果监控cadvisor 复制kubernetes-node job_name 将9100端口修改为cadvisor端口即可
target_label: __address__ #将[__address__]替换为__address__
action: replace #将替换后的值依然赋值给__address__
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
效果如下
node 常见指标
node_cpu_: CPU 相关指标
node_load1: load average #系统负载指标
node_load5
node_load15
node_memory_: 内存相关指标
node_network_: 网络相关指标
node_disk_: 磁盘 IO 相关指标
node_filesystem_: 文件系统相关指标
node_boot_time_seconds: 系统启动时间监控
go_*: node exporte 运行过程中 go 相关指标
process_*: node exporter 运行时进程内部进程指标
8.pod 发现及指标数据
8.1 通过cadvisor发现
- job_name: 'kubernetes-node-cadvisor' #这来抓取cadvisor数据通过 kubeapi,因为k8s已经内置了cadvisor,如果通过部署的DS获取,参考上面的 kubernetes-node job_name
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt #访问api-server需要认证,此处使用证书,相关证书和token已经自动挂载到pod中
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor #变量替换,将$1替换为node名称,名称从上面的regex 正则中获取
8.2直接发现
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
namespaces: #可选指定namepace,如果不指定就是发现所有的namespace中的pod
names:
- dev
- test
- pre
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
pod 常见指标
参考:https://help.aliyun.com/zh/prometheus/developer-reference/basic-metrics/ #Cadvisor任务类型(Job)的任务名称和基础指标
9.kube-scheduler服务发现
kube-scheduler是通过10259端口进行暴漏,查看kube-scheduler的配置文件,如果没有绑定在0.0.0.0,需要进行修改
如果是二进制则根据定义的配置文件路径修改,如果是systemd则修改/etc/systemd/system/kube-scheduler.service,我是kubeadm部署的测试环境修改/etc/kubernetes/manifests/kube-scheduler.yaml文件,修改后需要重启kubelet
prometheus配置如下:
- job_name: kube-scheduler
metrics_path: /metrics
scheme: https
tls_config:
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__meta_kubernetes_node_name]
regex: (k8s-master.*) #注意此处,匹配节点名称为k8s-master或以此为前缀的节点,需要根据时间情况进行修改
action: keep
- source_labels: [__meta_kubernetes_node_address_InternalIP] #当前节点的内网IP
regex: (.+)
target_label: __address__
replacement: ${1}:10259 #即节点的内网IP:10259 并赋值给__address__
- source_labels: [__meta_kubernetes_node_name]
action: replace
target_label: node_name
replacement: kube_scheduler_${1}
效果如下:
10.kube-proxy服务发现
kube-scheduler是通过10249端口进行暴漏,查看kube-scheduler的配置文件,如果没有绑定在0.0.0.0,需要进行修改
如果是二进制则根据定义的配置文件路径修改,如果是systemd则修改/etc/systemd/system/kube-proxy.service,我是kubeadm部署的测试环境kube-proxy为daemonsets方式部署,所以修改其配置文件
kubectl edit cm -n kube-system kube-proxy
metricsBindAddress: 0.0.0.0 #修改此行的值为0.0.0.0,修改收删除Proxy的pod
prometheus配置
- job_name: kube-proxy
metrics_path: /metrics
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: '(.*):10250'
replacement: '${1}:10249'
target_label: __address__
action: replace
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- source_labels: [__meta_kubernetes_endpoints_name]
action: replace
target_label: endpoint
- source_labels: [__meta_kubernetes_node_name]
action: replace
target_label: endpoint
replacement: kube-proxy-${1}
效果如下
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少