环境信息
kubectl versionClient Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.9", GitCommit:"a17149e1a189050796ced469dbd78d380f2ed5ef", GitTreeState:"clean", BuildDate:"2020-04-16T11:44:51Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.9", GitCommit:"a17149e1a189050796ced469dbd78d380f2ed5ef", GitTreeState:"clean", BuildDate:"2020-04-16T11:36:15Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
术语解释
- Endpoint:抓取目标实际访问的抓取地址,组成为:
__scheme__+__address__+__metrics_path__。因此,很多标签重写都是重写的其中之一,或者全部,例如,__address_以及__metrics_path_两个是高频重写点
原理解析
有的应用具有暴露容器内具体进程性能指标的需求,这些指标由应用侧实现采集并暴露,平台侧做汇聚。具体方案有如下两种:
- 业务应用自己暴露性能指标
- 通过Sidecar方式,集成相关exporter来暴露指标(本例属于此种方案)
此种方案中,一般还需要通过
__meta_kubernetes_endpoint_port_name进行进一步的过滤,仅仅保留Pod中通过sidecar方式打入的exporter容器端点才行,正常是不需要业务容器端点的
本例中,Prometheus自动发现K8S的EndPoint地址,同时,通过标签重写可以构造出Pod中部署的实际监控代理的抓取目标端点;例如,本例中我们将redis_exporter作为Sidecar容器一起部署到了redis本身所在的Pod中,因此,redis_exporter还需要监控localhost:6379即可,同时,也通过POD的IP暴露出自己的端点出来,供Prometheus服务器抓取指标数据之用。
如何标识哪些是主动暴露监控指标的应用并获取指标
平台侧可以约定好带哪些annotation前缀的服务是自主暴露监控指标的服务。应用添加平台侧约定的这些annotations,平台侧可以根据这些annotations实现Prometheus的scrape。
例如,应用侧为自己的服务添加如下平台侧约定约定的annotation:
prometheus.io/scrape: "true"prometheus.io/path: "/metrics"prometheus.io/port: "9121"prometheus.io/app-scrape: "true",过滤应用业务组件监控类型
如何给应用加一些自定义标记信息
可能还需要根据平台和业务的需求添加其他一些以prometheus.io/app-label-为前缀的annotation,Prometheus截取下前缀,保留后半部分做key,连同value保留下来。这样满足在平台对应用做其他一些标识的需求。比如加入如下annotation来标识应用所属的的环境、租户以及应用名称:
prometheus.io/app-label-env: "dev"prometheus.io/app-label-tenant: "hzero"prometheus.io/app-label-name: "redis-app"
Pod准备
mkdir -p /u01/repo/exportercd /u01/repo/exportervim prom-redis.yamlkubectl apply -f prom-redis.yaml
apiVersion: apps/v1kind: Deploymentmetadata:name: redisnamespace: kube-systemlabels:app: redisspec:selector:matchLabels:app: redistemplate:metadata:annotations:prometheus.io/scrape: "true"prometheus.io/path: "/metrics"prometheus.io/port: "9121"prometheus.io/app-scrape: "true"prometheus.io/app-label-env: "dev"prometheus.io/app-label-tenant: "hzero"prometheus.io/app-label-name: "redis-app"labels:app: redisspec:containers:- name: redisimage: redis:4resources:requests:cpu: 100mmemory: 100Miports:- containerPort: 6379- name: redis-exporterimage: oliver006/redis_exporter:latestresources:requests:cpu: 100mmemory: 100Miports:- containerPort: 9121---kind: ServiceapiVersion: v1metadata:name: redisnamespace: kube-systemspec:selector:app: redisports:- name: redisport: 6379targetPort: 6379- name: promport: 9121targetPort: 9121
几点需要注意:
- 此处的命名空间是
kube-system,那么,在Prometheus抓取任务中,K8S服务发现需要添加这个命名空间,否则无法抓取 - 业务侧需要增加三个元数据标签注解
- prometheus.io/scrape: “true”
- prometheus.io/path: “/metrics”
- prometheus.io/port: “9121”
- prometheus.io/app-scrape: “true”:过滤应用业务组件监控类型
- 业务侧可以按需增加自定义元数据标签注解(注意:按需在Pod上或者Service上)
- prometheus.io/app-label-env: “dev”
- prometheus.io/app-label-tenant: “hzero”
- prometheus.io/app-label-name: “redis-app”
- 访问方式
- 方式一:通过
apiserver proxy URLs方式访问(也即本例,推荐采用此种方案) - 方式二:Service维度需要通过
NodePort方式暴露redis_exporter的指标端口,例如,30021,也即prometheus.io/port注解的值,然后通过节点IP+NodePort方式访问
- 方式一:通过
此种方式需要将
__address_重写为:节点ID:prometheus.io/port,也即:
relabel_configs:- source_labels: [__address__, __meta_kubernetes_pod_host_ip,__meta_kubernetes_pod_annotation_prometheus_io_port]action: replaceregex: ([^:]+)(?::\d+)?;([^:]+);(\d+)replacement: $2:$3target_label: __address__
注意,正则表达式中,
?:开头的为非捕获组,因此,对于10.244.24.143:6379;172.23.16.106;30021来讲,$0代表整个表达式,$1代表10.244.24.143(因为第二段的6379为非捕获组(?::\d+)?),$2代表172.23.16.106,$3代表30021,最终构造出了172.23.16.106:30021。具体可参考正则表达式高级用法(分组与捕获)。一般的材料上直接替换了端口部分,IP部分仍然使用Pod的IP,这是因为有一个前提是,Prometheus本身就部署在了待监控K8S集群中,因此,可以访问到集群内的IP地址及端口信息,因此,也就不需要使用NodePort方式再做一层映射了。
- 我们自动发现的是EndPoint,而如果后端承载着Pod,则可以获取到Pod的标签注解,因此,只需要Pod上有相关标签注解即可。Service暂时是不需要的。下一节探测Service时会添加上;那么,此处为什么又要有Service呢?是为了对外暴露后端Pod服务的。
- 抓取任务中,协议为
http
核心配置项解析
抓取任务配置
| 任务编码 | 指标路径 | 协议 | 请求参数 | 认证授权及TLS | 说明 |
|---|---|---|---|---|---|
| K8S-APP-CUSTOM | /metrics | https | - | Token认证,禁用验证服务器端证书 | 访问协议为https |
K8S服务发现配置
| 资源类型 | API Server地址 | 命名空间 | 认证授权及TLS | 说明 |
|---|---|---|---|---|
| endpoints | https://172.23.16.106:8443 | default,kube-system | Token认证,禁用验证服务器端证书 | API Server地址此处配置的是负载均衡地址,命名空间正常讲应该留空,代表所有空间;本例中我们构造的Pod在kube-system命名空间中,因此需要将其纳入进来 |
标签重写配置
K8S-APP-CUSTOM
标签重写主要关注如下几点:
- 需要过滤掉不需要监控的端点,仅保留
prometheus.io/scrape: true、prometheus.io/app-scrape: true及__meta_kubernetes_endpoint_port_name: prom的端点;至于是在Pod上还是Service上,需要视情况而定,本例中打在了Pod上。
特别注意:一定需要通过
__meta_kubernetes_endpoint_port_name限制端口名称,否则,在本例中,同一个Pod通过Sidecar方式既运行了业务容器Redis,也同时运行了监控组件redis-exporter,那么,依据endpoints角色的发现机制,会同时发现两个端点抓取目标,但是实际上我们只需要redis-exporter的这条数据,通过端口名称过滤可以解决这个问题(同一个Pod多个端口时,K8S要求必须指定端口名称)。
- 将
instance标签设置为原始的抓取目标地址,也即保留原始抓取目标地址 - 将
__address__标签设置为API Server的地址,因为,本例中通过apiserver proxy URLs方式实现监控 - 替换
__metrics_path__为apiserver proxy URLs,注意,此处的端口部分必须是prometheus.io/port指定的端口,而不能是__meta_kubernetes_pod_container_port_number,此Pod将会存在多个容器、多个端口 - 添加额外的富有含义的指标标签
- 生成
命名空间标签 - 生成
服务名标签 - 添加额外的业务含义的指标标签
| 序号 | 重写动作 | 来源标签名称 | 分隔符 | 正则匹配 | Hash模数 | 目标标签名称 | 目标标签替换值 |
| —- | —- | —- | —- | —- | —- | —- | —- |
| 0 | 保持 |
[__meta_kubernetes_pod_annotation_prometheus_io_scrape,__meta_kubernetes_pod_annotation_prometheus_io_app_scrape,__meta_kubernetes_endpoint_port_name]| | true;true;prom | | | | | 1 | 替换 |[__address__]| | | |instance| | | 2 | 替换 | | | | |__address__| 172.23.16.106:8443 | | 3 | 替换 |[__meta_kubernetes_namespace, __meta_kubernetes_pod_name, __meta_kubernetes_pod_annotation_prometheus_io_port]| |([^;]+);([^;]+);([^;]+)| |__metrics_path__|/api/v1/namespaces/${1}/pods/http:${2}:${3}/proxy/metrics| | 4 | 标签映射 | | | |__meta_kubernetes_pod_label_(.+)| | | | 5 | 替换 |[__meta_kubernetes_namespace]| | | | kubernetesnamespace | | | 6 | 替换 |[__meta_kubernetes_pod_name]| | | | kubernetes_pod_name | | | 7 | 标签映射 | | | | `__meta_kubernetes_pod_annotation_prometheus_io_app_label(.+)` | | |
最终抓取任务配置
- job_name: K8S-APP-CUSTOMhonor_timestamps: truescrape_interval: 1mscrape_timeout: 10smetrics_path: /metricsscheme: httpsfile_sd_configs:- files:- /u01/prometheus/target/nodes/K8S-APP-CUSTOM_targets_hosts.jsonrefresh_interval: 5mkubernetes_sd_configs:- api_server: https://172.23.16.106:8443role: endpointsbearer_token: <secret>tls_config:insecure_skip_verify: truenamespaces:names:- default- kube-systembearer_token: <secret>tls_config:insecure_skip_verify: truerelabel_configs:- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape, __meta_kubernetes_pod_annotation_prometheus_io_app_scrape,__meta_kubernetes_endpoint_port_name]separator: ;regex: true;true;promreplacement: $1action: keep- source_labels: [__address__]separator: ;regex: (.*)target_label: instancereplacement: $1action: replace- separator: ;regex: (.*)target_label: __address__replacement: 172.23.16.106:8443action: replace- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_pod_name, __meta_kubernetes_pod_annotation_prometheus_io_port]separator: ;regex: ([^;]+);([^;]+);([^;]+)target_label: __metrics_path__replacement: /api/v1/namespaces/${1}/pods/http:${2}:${3}/proxy/metricsaction: replace- separator: ;regex: __meta_kubernetes_pod_label_(.+)replacement: $1action: labelmap- source_labels: [__meta_kubernetes_namespace]separator: ;regex: (.*)target_label: kubernetes_namespacereplacement: $1action: replace- source_labels: [__meta_kubernetes_pod_name]separator: ;regex: (.*)target_label: kubernetes_pod_namereplacement: $1action: replace- separator: ;regex: __meta_kubernetes_pod_annotation_prometheus_io_app_label_(.+)replacement: $1action: labelmap- separator: ;regex: (.*)target_label: PersonNumreplacement: hopsaction: replace- separator: ;regex: (.*)target_label: _tenant_idreplacement: "0"action: replace
验证预览

注意:其中的
env、name、tenant均是业务含义的自定义指标标签。同时仅保留了instance=10.244.46.126:9121也即redis-exporter的容器端点。
结论
此种方案适合于node_exporter、redis_exporter等手工打到Pod容器当中的监控代理自动发现方式。
