Kubernetes Prometheus Discovery
概述¶
KubernetesPrometheus 是一个只能应用在 Kubernetes 的采集器,它根据自定义配置实现自动发现 Prometheus 服务并进行采集,极大简化了使用过程。
本采集器需要对 Kubernetes 一定的熟悉程度,例如能通过 kubectl 命令查看 Services、Pods 等资源的各项属性。
简述本采集器的实现方式,能更好的了解和使用采集器。 KubernetesPrometheus 的实现主要有以下几步:
- 对 Kubernetes APIServer 注册事件通知机制,能及时获知各类资源的创建、更新和删除情况
- 当某个资源(例如 Pod)被创建时,KubernetesPrometheus 会接收到通知,根据配置文件决定是否对该 Pod 进行采集
- 如果该 Pod 符合条件,依照配置文件的占位符找到 Pod 对应属性(例如 Port 等),构建一个访问地址
- KubernetesPrometheus 会访问该地址,将数据进行解析和添加标签
- 如果该 Pod 发生更新或删除,KubernetesPrometheus 采集器会终止对该 Pod 的采集,再根据具体情况判断是否开启新采集
配置说明¶
- 以下是一份最基础的配置,它只有 2 个配置项——选择自发现的目标是 Pod,和指定目标 Port。它实现了对所有 Pods 的 Prometheus 数据采集,即使它们并没有 export Prometheus 数据:
[[inputs.kubernetesprometheus.instances]]
role = "pod"
port = "__kubernetes_pod_container_nginx_port_metrics_number"
- 对上面的配置进行补充,不再采集所有 Pods,而是按照 Namespace 和 Selector 指定某一类 Pod。如配置所示,现在只采集 Namespace 是
middleware
且存在 Label 是app=nginx
的 Pods:
[[inputs.kubernetesprometheus.instances]]
role = "pod"
namespaces = ["middleware"]
selector = "app=nginx"
port = "__kubernetes_pod_container_nginx_port_metrics_number"
- 再次对配置进行补充,这次要添加一些标签。标签值是动态的,根据目标 Pod 的属性取值。此处添加了 4 个标签:
[[inputs.kubernetesprometheus.instances]]
role = "pod"
namespaces = ["middleware"]
selector = "app=nginx"
port = "__kubernetes_pod_container_nginx_port_metrics_number"
[inputs.kubernetesprometheus.instances.custom]
[inputs.kubernetesprometheus.instances.custom.tags]
instance = "__kubernetes_mate_instance"
host = "__kubernetes_mate_host"
pod_name = "__kubernetes_pod_name"
pod_namespace = "__kubernetes_pod_namespace"
- 如果目标 Pod 的 Prometheus 服务是 https 协议,还需要额外配置认证证书,这些证书已经提前挂载进 Datakit 容器中:
[[inputs.kubernetesprometheus.instances]]
role = "pod"
namespaces = ["middleware"]
selector = "app=nginx"
scheme = "https"
port = "__kubernetes_pod_container_nginx_port_metrics_number"
[inputs.kubernetesprometheus.instances.custom]
[inputs.kubernetesprometheus.instances.custom.tags]
instance = "__kubernetes_mate_instance"
host = "__kubernetes_mate_host"
pod_name = "__kubernetes_pod_name"
pod_namespace = "__kubernetes_pod_namespace"
[inputs.kubernetesprometheus.instances.auth]
[inputs.kubernetesprometheus.instances.auth.tls_config]
insecure_skip_verify = false
ca_certs = ["/opt/nginx/ca.crt"]
cert = "/opt/nginx/peer.crt"
cert_key = "/opt/nginx/peer.key"
- 最后,这是一份完整的配置,它包含了所有的配置项:
[[inputs.kubernetesprometheus.instances]]
role = "pod"
namespaces = ["middleware"]
selector = "app=nginx"
scrape = "true"
scheme = "https"
port = "__kubernetes_pod_container_nginx_port_metrics_number"
path = "/metrics"
params = ""
[inputs.kubernetesprometheus.instances.custom]
measurement = "pod-nginx"
job_as_measurement = false
[inputs.kubernetesprometheus.instances.custom.tags]
instance = "__kubernetes_mate_instance"
host = "__kubernetes_mate_host"
pod_name = "__kubernetes_pod_name"
pod_namespace = "__kubernetes_pod_namespace"
[inputs.kubernetesprometheus.instances.auth]
bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token"
[inputs.kubernetesprometheus.instances.auth.tls_config]
insecure_skip_verify = false
ca_certs = ["/opt/nginx/ca.crt"]
cert = "/opt/nginx/peer.crt"
cert_key = "/opt/nginx/peer.key"
此外还有一类全局配置,它是最顶层的配置,主要负责一些功能开启或关闭,以及给全部 instances 添加标签:
[inputs.kubernetesprometheus]
node_local = true # 开启 NodeLocal 模式,将采集分散到各个节点
scrape_interval = "30s" # 指定采集间隔,默认是 30 秒
enable_discovery_of_prometheus_pod_annotations = false # 开启预定义的 Pod Annotations 配置
enable_discovery_of_prometheus_service_annotations = false # 开启预定义的 Service Annotations 配置
enable_discovery_of_prometheus_pod_monitors = false # 开启 Prometheus PodMonitors CRD 功能
enable_discovery_of_prometheus_service_monitors = false # 开启 Prometheus ServiceMonitors CRD 功能
[inputs.kubernetesprometheus.global_tags]
cluster_name_k8s = "$(ENV_CLUSTER_NAME_K8S)"
instance = "__kubernetes_mate_instance"
host = "__kubernetes_mate_host"
[[inputs.kubernetesprometheus.instances]]
# ..other
global_tags
会给全部 instance 添加 tags,有以下几点要说明:
- 只支持
__kubernetes_mate_instance
和__kubernetes_mate_host
两个占位符,具体功能请查看后文 - 支持环境变量配置方式,例如
$(NAME)
和myname=$(NAME)
,如果能找到NAME
这个环境变量,就进行替换。如果找不到,保持$(NAME)
字符串原样 - 环境变量方式只支持小括号
- 不支持同一个字符串有多个环境变量,例如写成
name=$(NAME),namespace=$(NAMESPACE)
,只有$(NAME)
有效
Attention
不需要手动配置 IP,采集器会使用默认 IP,具体是:
node
使用 InternalIPPod
使用 Pod IPService
使用对应 Endpoints 的 Address IP(多个)Endpoints
使用对应 Address IP(多个)
另外需要注意,端口不能绑定到环回地址,否则外部无法访问。
假设这个 Pod IP 是 172.16.10.10
,容器 nginx 的 metrics 端口是 9090。
最终 KubernetesPrometheus 采集器会创建一个目标地址是 http://172.16.10.10:9090/metrics
的 Prometheus 采集,解析数据后添加标签 pod_name
和 pod_namespace
,指标集名称是 pod-nginx
。
如果存在另一个 Pod 也符合 namespace 和 selector 配置,那么也采集它。
配置详解¶
KubernetesPrometheus 采集器主要使用占位符进行配置,只保留最基础的、实现采集的必要配置(例如 port、path 等),现在逐个说明各个配置项的含义。
以上文的配置为例,其中:
主配置¶
配置项 | 是否必要 | 默认值 | 描述 | 是否支持占位符 |
---|---|---|---|---|
role |
Yes | 无 | 指定采集的资源类型,只能是 node 、pod 、service 和 endpoints 任意一个 |
No |
namespace |
No | 无 | 限定这个资源所属的命名空间,它是个数组,可以写多个,例如 ["kube-system", "testing"] |
No |
selector |
No | 无 | labels 查询和过滤,它的范围更小、更精确。它是一个字符串,支持 '=', '==', '!=' ,例如 key1=value1,key2=value2 |
No |
scrape |
No | "true" | 判定是否要采集。当它为空字符串或为 true 时,会执行采集,否则不采集 |
Yes |
scheme |
No | "http" | 默认值是 http ,如果采集需要用到证书,应改为 https |
Yes |
port |
Yes | 无 | 目标地址的端口,需要手动配置 | Yes |
path |
No | "/metrics" | http 访问路径,默认值是 /metrics |
Yes |
params |
No | 无 | http 访问参数,是一个字符串,例如 name=nginx&package=middleware |
No |
selector
在 kubectl 命令行经常使用,例如要查找 labels 包含tier=control-plane
和component=kube-controller-manager
的 Pod,可以使用以下命令:$ kubectl get pod --selector tier=control-plane,component=kube-controller-manager
--selector
参数和selector
配置项作用相同,更多编写方式见官方文档。
定制化配置¶
配置项 | 是否必要 | 默认值 | 描述 |
---|---|---|---|
measurement |
No | 对指标字段名的第一条下划线切割所得 | 配置指标集名称 |
job_as_measurement |
No | false | 是否使用数据中的 job 标签值当做指标集名称 |
tags |
No | 无 | 添加标签,注意标签的 key 不支持占位符,value 支持占位符,详见后文的占位符描述 |
Attention
KubernetesPrometheus 采集器不添加任何默认标签,包括来自 Datakit 的 election_tags
和 host_tags
,以及 cluster_name_k8s
。
所有标签都需要手动添加。
权限和验证¶
bearer_token_file
配置 token 文件路径,通常和insecure_skip_verify
一起用tls_config
配置证书相关,子配置项分别是insecure_skip_verify
、ca_certs
、cert
、cert_key
,需要注意ca_certs
是个数组配置
占位符说明¶
占位符是整个采集方案中非常重要的一部分。它本身是一个字符串,指向了资源的某个属性。
占位符主要有 2 类,即“固定匹配”和“通配匹配”:
- 固定匹配,类似
__kubernetes_pod_name
,它是唯一的,只指向该 Pod Name,简单明了 - 通配匹配,用来配置一些自定义资源名,在下文中以
%s
代替。例如,Pod 有个 Label 是app=nginx
,需要把nginx
取出来当做标签,要这样配置:
为什么要有这一步?
因为这个 label 的值不是固定的,根据 Pod 不同会有变化。在这个 Pod 是 app=nginx
,在另一个 Pod 可能是 app=redis
,如果要用同一份配置采集这 2 个 Pod,必然要对它们进行标签区分,就可以用这种配置方式。
占位符更多用在 annotation
和 label
的选择上,另外配置 port 也用到占位符。例如,Pod 有个容器叫 nginx,该容器有个 port 叫 metrics
,现在采集这个端口,可以写成 __kubernetes_pod_container_nginx_port_metrics_number
。
以下是全局占位符和各类资源(node
、pod
、service
、endpoints
)支持的占位符。
全局占位符¶
全局占位符是所有 Role 通用,多用来指定一些特殊标签。
Name | Description | 使用范围 |
---|---|---|
__kubernetes_mate_instance | 采集目标的 instance,即 IP:PORT |
仅支持在 custom.tags 使用,例如 instance = "__kubernetes_mate_instance" |
__kubernetes_mate_host | 采集目标的 host,即 IP 。如果该值是 localhost 或环回地址将不再添加 |
仅支持在 custom.tags 使用,例如 host = "__kubernetes_mate_host" |
Node Role¶
此类资源的采集地址是 InternalIP,对应 JSONPath 是 .status.addresses[*].address ("type" is "InternalIP")
。
Name | Description | 对应的 JSONPath |
---|---|---|
__kubernetes_node_name | Node 名称 | .metadata.name |
__kubernetes_node_label_%s | Node 标签 | .metadata.labels['%s'] |
__kubernetes_node_annotation_%s | Node 注解 | .metadata.annotations['%s'] |
__kubernetes_node_address_Hostname | Node 主机名 | .status.addresses[*].address ("type" is "Hostname") |
__kubernetes_node_kubelet_endpoint_port | Node 的 kubelet 端口,一般都是 10250 | .status.daemonEndpoints.kubeletEndpoint.Port |
Pod Role¶
此类资源的采集地址是 PodIP,对应 JSONPath 是 .status.podIP
。
Name | Description | 对应的 JSONPath |
---|---|---|
__kubernetes_pod_name | Pod 名称 | .metadata.name |
__kubernetes_pod_namespace | Pod 命名空间 | .metadata.namespace |
__kubernetes_pod_label_%s | Pod 标签,例如 _kubernetes_pod_label_app |
.metadata.labels['%s'] |
__kubernetes_pod_annotation_%s | Pod 注解,例如 _kubernetes_pod_annotation_prometheus.io/port |
.metadata.annotations['%s'] |
__kubernetes_pod_node_name | Pod 所属的 Node | .spec.nodeName |
__kubernetes_pod_container_%s_port_%s_number | 指定 container 的指定 port,例如 __kubernetes_pod_container_nginx_port_metrics_number 指向 nginx 容器的 metrics 端口 |
.spec.containers[].ports[].containerPort ("name" equal "%s") |
对于 __kubernetes_pod_container_%s_port_%s_number 举例:
现有 Pod nginx,它有 2 个容器,分别是 nginx 和 logfwd,现在要采集 nginx 容器的 8080 端口(假设配置中 8080 端口叫做 metrics),那么可以配置为:
__kubernetes_pod_container_nginx_port_metrics_number
(注意 nginx 和 metrics 把 %s 替换了)
Service Role¶
Service 资源没有 IP 属性,所以使用跟它对应的 Endpoints Address IP 属性(存在多个),JSONPath 是 Endpoints .subsets[*].addresses[*].ip
。
Name | Description | 对应的 JSONPath |
---|---|---|
__kubernetes_service_name | Service 名称 | .metadata.name |
__kubernetes_service_namespace | Service 命名空间 | .metadata.namespace |
__kubernetes_service_label_%s | Service 标签 | .metadata.labels['%s'] |
__kubernetes_service_annotation_%s | Service 注解 | .metadata.annotations['%s'] |
__kubernetes_service_port_%s_port | 指定 port(基本用不到,大部分场景都使用 targetPort) | .spec.ports[*].port ("name" equal "%s") |
__kubernetes_service_port_%s_targetport | 指定 targetPort | .spec.ports[*].targetPort ("name" equal "%s") |
__kubernetes_service_target_kind | Service 中没有 target,这是指向对应 endpoints 的 targetRef,取它的 kind 字段 |
Endpoints: .subsets[].addresses[].targetRef.kind |
__kubernetes_service_target_name | Service 中没有 target,这是指向对应 endpoints 的 targetRef,取它的 name 字段 |
Endpoints: .subsets[].addresses[].targetRef.name |
__kubernetes_service_target_namespace | Service 中没有 target,这是指向对应 endpoints 的 targetRef,取它的 namespace 字段 |
Endpoints: .subsets[].addresses[].targetRef.namespace |
__kubernetes_service_target_pod_name | Deprecated, 请使用 __kubernetes_service_target_name |
Endpoints: .subsets[].addresses[].targetRef.name |
__kubernetes_service_target_pod_namespace | Deprecated, 请使用 __kubernetes_service_target_namespace |
Endpoints: .subsets[].addresses[].targetRef.namespace |
Endpoints Role¶
此类资源的采集地址是 Address IP(存在多个),对应 JSONPath 是 .subsets[*].addresses[*].ip
。
Name | Description | 对应的 JSONPath |
---|---|---|
__kubernetes_endpoints_name | Endpoints 名称 | .metadata.name |
__kubernetes_endpoints_namespace | Endpoints 命名空间 | .metadata.namespace |
__kubernetes_endpoints_label_%s | Endpoints 标签 | .metadata.labels['%s'] |
__kubernetes_endpoints_annotation_%s | Endpoints 注解 | .metadata.annotations['%s'] |
__kubernetes_endpoints_address_node_name | Endpoints Address 的 Node 名称 | .subsets[].addresses[].nodeName |
__kubernetes_endpoints_address_target_kind | targetRef 的 kind 字段 |
.subsets[].addresses[].targetRef.kind |
__kubernetes_endpoints_address_target_name | targetRef 的 name 字段 |
.subsets[].addresses[].targetRef.name |
__kubernetes_endpoints_address_target_namespace | targetRef 的 namespace 字段 |
.subsets[].addresses[].targetRef.namespace |
__kubernetes_endpoints_address_target_pod_name | Deprecated, 请使用 __kubernetes_endpoints_address_target_name |
.subsets[].addresses[].targetRef.name |
__kubernetes_endpoints_address_target_pod_namespace | Deprecated, 请使用 __kubernetes_endpoints_address_target_namespace |
.subsets[].addresses[].targetRef.namespace |
__kubernetes_endpoints_port_%s_number | 指定 port 名称,例如 __kubernetes_endpoints_port_metrics_number |
.subsets[].ports[].port ("name" equal "%s") |
实际案例¶
以下例子会创建一个 Service 和 Deployment,使用 KubernetesPrometheus 采集对应的 Pod。步骤如下:
- 创建 Service 和 Deployment
apiVersion: v1
kind: Service
metadata:
name: prom-svc
namespace: testing
labels:
app.kubernetes.io/name: prom
spec:
selector:
app.kubernetes.io/name: prom
ports:
- name: metrics
protocol: TCP
port: 8080
targetPort: 30001
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prom-server
namespace: testing
spec:
selector:
matchLabels:
app.kubernetes.io/name: prom
replicas: 1
template:
metadata:
labels:
app.kubernetes.io/name: prom
spec:
containers:
- name: prom-server
image: pubrepo.guance.com/datakit-dev/prom-server:v2
imagePullPolicy: IfNotPresent
env:
- name: ENV_PORT
value: "30001"
- name: ENV_NAME
value: "promhttp"
ports:
- name: metrics
containerPort: 30001
- 创建 ConfigMap 和 KubernetesPrometheus 配置
apiVersion: v1
kind: ConfigMap
metadata:
name: datakit-conf
namespace: datakit
data:
kubernetesprometheus.conf: |-
[inputs.kubernetesprometheus]
[[inputs.kubernetesprometheus.instances]]
role = "service"
namespaces = ["testing"]
selector = "app.kubernetes.io/name=prom"
scrape = "true"
scheme = "http"
port = "__kubernetes_service_port_metrics_targetport"
path = "/metrics"
params = ""
[inputs.kubernetesprometheus.instances.custom]
measurement = "prom-svc"
job_as_measurement = false
[inputs.kubernetesprometheus.instances.custom.tags]
svc_name = "__kubernetes_service_name"
pod_name = "__kubernetes_service_target_name"
pod_namespace = "__kubernetes_service_target_namespace"
- 在 Datakit yaml 中应用
kubernetesprometheus.conf
文件
# ..other..
volumeMounts:
- mountPath: /usr/local/datakit/conf.d/kubernetesprometheus/kubernetesprometheus.conf
name: datakit-conf
subPath: kubernetesprometheus.conf
readOnly: true
- 最后启动 Datakit,在日志中能看到
create prom url xxxxx for testing/prom-svc
的内容,并在观测云页面看到prom-svc
指标集。