17.3.4 Kubernetes服务发现与标签选择

Kubernetes 服务发现机制概览#

Prometheus 通过 Kubernetes API 自动发现集群内的监控目标,支持 Pod、Service、Endpoints、Node、Ingress 等资源类型。其核心流程是:拉取 API 元数据 → relabel 过滤与重写 → 生成实际抓取目标。
下图为原理草图:

文章图片

典型发现配置示例#

以下示例基于 kube-prometheus 或自建 Prometheus,演示 Pod 发现、标签筛选与注解参数化。
文件路径:/etc/prometheus/prometheus.yml

scrape_configs:
  - job_name: "k8s-pods"
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      # 仅保留显式标记 scrape=true 的 Pod
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: "true"

      # 从注解中读取采集端口
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: "(.+)"
        replacement: "$1"
        # __address__ 先只放端口,稍后拼接 IP
      - source_labels: [__meta_kubernetes_pod_ip, __address__]
        action: replace
        target_label: __address__
        regex: "(.+);(.+)"
        replacement: "$1:$2"

      # 自定义采集路径
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: "(.+)"
        replacement: "$1"

      # 标签映射:namespace、pod、app
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: namespace
      - source_labels: [__meta_kubernetes_pod_name]
        action: replace
        target_label: pod
      - source_labels: [__meta_kubernetes_pod_label_app]
        action: replace
        target_label: app

命令验证配置生效:

# 重新加载 Prometheus 配置(需启用 --web.enable-lifecycle)
curl -X POST http://prometheus:9090/-/reload

# 查看发现到的目标
curl -s http://prometheus:9090/api/v1/targets | jq '.data.activeTargets[].labels'

标签选择与注解约定#

推荐约定统一使用以下注解与标签:

metadata:
  labels:
    app: order-api
    env: prod
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/metrics"

创建示例 Pod:

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: demo-metrics
  labels:
    app: demo
    env: dev
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9100"
    prometheus.io/path: "/metrics"
spec:
  containers:
  - name: node-exporter
    image: prom/node-exporter:v1.6.1
    ports:
    - containerPort: 9100
EOF

relabeling 规则与目标过滤#

常见 relabel 动作说明:
- keep:仅保留符合条件的目标
- drop:丢弃符合条件的目标
- replace:重写或新增标签

示例:仅保留 env=prod 的 Pod,同时丢弃临时命名空间:

relabel_configs:
  - source_labels: [__meta_kubernetes_pod_label_env]
    action: keep
    regex: "prod"
  - source_labels: [__meta_kubernetes_namespace]
    action: drop
    regex: "tmp|sandbox"

多资源发现与使用场景#

不同资源发现类型的实践建议:

# 监控 Node(配合 node-exporter DaemonSet)
- job_name: "k8s-nodes"
  kubernetes_sd_configs:
    - role: node
  scheme: http
  relabel_configs:
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)

适用场景:
- pod:微服务实例级监控,便于细粒度定位问题
- endpoints:基于 Service 后端实例发现
- service:用于 blackbox 或对外服务健康检测
- node:主机层指标
- ingress:入口可用性监控

标签管理与一致性规范#

统一标签规范示例:

必须标签:namespace, app, pod, cluster
建议标签:env, version, release
避免标签:request_idtrace_iduser_id(高基数)

命令检查标签基数(估算):

# 查询某指标的不同 label 值数量
curl -G 'http://prometheus:9090/api/v1/series' \
  --data-urlencode 'match[]=up' \
  --data-urlencode 'start=1h' \
  --data-urlencode 'end=now' | jq '.data | length'

安装与权限配置示例#

Kubernetes 中 Prometheus 需具备访问 API 的 RBAC 权限。
示例(最小权限):

apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-sd
rules:
- apiGroups: [""]
  resources: ["nodes", "services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["extensions", "networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-sd
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus-sd
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: monitoring

应用并验证:

kubectl apply -f rbac.yaml
kubectl -n monitoring get sa prometheus
kubectl auth can-i list pods --as system:serviceaccount:monitoring:prometheus

常见问题与排查思路#

  1. 未采集到指标
    - 检查 Pod 注解是否正确:
    bash kubectl get pod demo-metrics -o jsonpath='{.metadata.annotations}'
    - 检查 Prometheus 发现页面:http://prometheus:9090/service-discovery

  2. 目标状态为 DOWN
    - 校验端口/路径:
    bash kubectl exec -it demo-metrics -- wget -qO- localhost:9100/metrics | head
    - 检查网络策略或 Service 访问限制

  3. 目标过多导致资源消耗
    - 检查是否缺少 keep 规则
    - 查看目标数量:
    bash curl -s http://prometheus:9090/api/v1/targets | jq '.data.activeTargets | length'

练习#

  1. 新建一个 env=prod 的应用 Pod,添加 prometheus.io/scrape=true 注解,验证其出现在 /-/targets
  2. 修改 relabel 规则,仅保留 app=demo 的 Pod,观察 activeTargets 数量变化。
  3. 使用 role: endpoints 替换 role: pod,对比两种方式的目标标签差异。