使用 CRD 从 Kubernetes 集群创建自定义 Prometheus 抓取作业

自定义从您的 Kubernetes 集群中抓取 Prometheus 指标,文中描述了如何使用 ConfigMap 自定义从 Kubernetes 集群中默认目标收集 Prometheus 指标的方式。 本文介绍如何使用自定义资源定义(CRD)创建自定义抓取任务,以实现进一步的自定义和扩展额外的目标。

自定义资源定义 (CRD)

为 Prometheus 启用 Azure Monitor 托管服务会自动为 Pod 监视器和服务监视器部署自定义资源定义(CRD)。 这些 CRD 与 OsS Pod 监视器 和 Prometheus 的 OSS 服务监视器 相同,但组名称的更改除外。 如果你的群集上存在现有的 Prometheus CRD 和自定义资源,则这些 CRD 不会与加载项创建的 CRD 冲突。 同时,托管的 Prometheus 加载项无法识别为 OSS Prometheus 创建的 CRD。 这种分离是有意而为的,目的是隔离抓取作业。

创建 Pod 或服务监视器

使用 Pod 和服务监视器模板并遵循 API 规范来创建自定义资源(Pod 监视器服务监视器)。 托管 Prometheus 选取现有 OSS CR(自定义资源)所需的唯一更改是 API 组 - azmonitoring.coreos.com/v1

重要

请确保使用模板中指定的 labelLimit、labelNameLengthLimit 和 labelValueLengthLimit ,以便在处理过程中不会删除它们。 有关此文件不同部分的详细信息,请参阅下面的抓取配置设置

你的 Pod 和 ServiceMonitor 应类似于以下示例:

Pod 监视器示例

# Note the API version is azmonitoring.coreos.com/v1 instead of monitoring.coreos.com/v1
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor

# Can be deployed in any namespace
metadata:
  name: reference-app
  namespace: app-namespace
spec:
  labelLimit: 63
  labelNameLengthLimit: 511
  labelValueLengthLimit: 1023

  # The selector specifies which pods to filter for
  selector:

    # Filter by pod labels
    matchLabels:
      environment: test
    matchExpressions:
      - key: app
        operator: In
        values: [app-frontend, app-backend]

    # [Optional] Filter by pod namespace. Required if service is in another namespace.
    namespaceSelector:
      matchNames: [app-frontend, app-backend]

  # [Optional] Labels on the pod with these keys will be added as labels to each metric scraped
  podTargetLabels: [app, region, environment]

  # Multiple pod endpoints can be specified. Port requires a named port.
  podMetricsEndpoints:
    - port: metricscs from the exa

服务监视器示例

# Note the API version is azmonitoring.coreos.com/v1 instead of monitoring.coreos.com/v1
apiVersion: azmonitoring.coreos.com/v1
kind: ServiceMonitor

# Can be deployed in any namespace
metadata:
  name: reference-app
  namespace: app-namespace
spec:
  labelLimit: 63
  labelNameLengthLimit: 511
  labelValueLengthLimit: 1023

  # The selector filters endpoints by service labels.
  selector:
    matchLabels:
      app: reference-app

  # Multiple endpoints can be specified. Port requires a named port.
  endpoints:
  - port: metrics

部署 Pod 或服务监视器

按照以下示例中的 kubectl apply 部署 Pod 或服务监控器。

创建一个简单的应用程序

部署一个示例应用程序,用于公开 Pod/服务监视器所要配置的 Prometheus 指标。

kubectl apply -f https://raw.githubusercontent.com/Azure/prometheus-collector/refs/heads/main/internal/referenceapp/prometheus-reference-app.yaml
创建 PodMonitor 和/或 ServiceMonitor 以采集指标

部署配置为从上一步中抓取应用程序的 Pod 监视器。

Pod 监视器
kubectl apply -f https://raw.githubusercontent.com/Azure/prometheus-collector/refs/heads/main/otelcollector/deploy/example-custom-resources/pod-monitor/pod-monitor-reference-app.yaml
服务监视器
kubectl apply -f https://raw.githubusercontent.com/Azure/prometheus-collector/refs/heads/main/otelcollector/deploy/example-custom-resources/service-monitor/service-monitor-reference-app.yaml

故障排除

成功应用 Pod 或服务监视器后,加载项应自动开始从目标收集指标。 有关自定义资源的常规故障排除,请参阅 Azure Monitor 中的 Prometheus 指标集合 ,并确保目标显示在 127.0.0.1/目标中。

擦除配置设置

以下部分介绍 CRD 中使用的 Prometheus 配置文件中支持的设置。 有关这些设置的更多详细信息,请参阅 Prometheus 配置参考

全局设置

全局设置的配置格式与 OSS prometheus 配置支持的格式相同

global:
  scrape_interval: <duration>
  scrape_timeout: <duration>
  external_labels:
    <labelname1>: <labelvalue>
    <labelname2>: <labelvalue>
scrape_configs:
  - <job-x>
  - <job-y>

在全局部分中提供的设置适用于 CRD 中的所有抓取任务,但如果在单个作业中有特别指定,则这些设置会被覆盖。

注释

如果要使用应用于所有擦除作业的全局设置,并且只有自定义资源,则仍需仅使用全局设置创建 ConfigMap。 在自定义资源中,每个资源的设置将覆盖全局设置中的这些设置。

抓取配置

目前支持的自定义资源目标发现方法是 Pod 和服务监视器。

Pod 和服务监视器

使用 Pod 和服务监视器发现的目标具有不同的 __meta_* 标签,具体取决于使用的监视器。 可以使用 relabelings 部分的标签来筛选目标或替换目标的标签。 请参阅 Pod 和服务监视器示例了解 Pod 和服务监视器。

重复标签

relabelings 部分在发现目标时被使用,并适用于该作业的所有目标。 以下示例演示了如何使用 relabelings

添加标签向作业的每个指标添加一个具有值example_label的新标签example_value。 仅使用 __address__ 作为源标签,因为该标签始终存在,并为作业的每个目标添加标签。

relabelings:
- sourceLabels: [__address__]
  targetLabel: example_label
  replacement: 'example_value'

使用 Pod 或服务监控器标签

使用 Pod 和服务监视器发现的目标具有不同的 __meta_* 标签,具体取决于使用的监视器。 发现目标后,会删除 __* 标签。 若要在指标级别使用它们进行筛选,请先通过使用 relabelings 并分配标签名称来保留它们, 然后使用 metricRelabelings 进行筛选。

# Use the kubernetes namespace as a label called 'kubernetes_namespace'
relabelings:
- sourceLabels: [__meta_kubernetes_namespace]
  action: replace
  targetLabel: kubernetes_namespace

# Keep only metrics with the kubernetes namespace 'default'
metricRelabelings:
- sourceLabels: [kubernetes_namespace]
  action: keep
  regex: 'default'

作业和实例重命名

可以根据源标签更改 jobinstance 标签值,就像任何其他标签一样。

# Replace the job name with the pod label 'k8s app'
relabelings:
- sourceLabels: [__meta_kubernetes_pod_label_k8s_app]
  targetLabel: job

# Replace the instance name with the node name. This is helpful to replace a node IP
# and port with a value that is more readable
relabelings:
- sourceLabels: [__meta_kubernetes_node_name]
  targetLabel: instance

注释

如果你有重新标记配置,请确保重新标记不会筛选掉目标,并且配置的标签与目标正确匹配。

指标重命名

指标重新标记在抓取之后、引入之前应用。 使用 metricRelabelings 部分在抓取之后筛选指标。 请参阅以下示例。

按名称删除指标

# Drop the metric named 'example_metric_name'
metricRelabelings:
- sourceLabels: [__name__]
  action: drop
  regex: 'example_metric_name'

仅按名称保留某些指标

# Keep only the metric named 'example_metric_name'
metricRelabelings:
- sourceLabels: [__name__]
  action: keep
  regex: 'example_metric_name'
# Keep only metrics that start with 'example_'
metricRelabelings:
- sourceLabels: [__name__]
  action: keep
  regex: '(example_.*)'

按标签筛选指标

# Keep metrics only where example_label = 'example'
metricRelabelings:
- sourceLabels: [example_label]
  action: keep
  regex: 'example'
# Keep metrics only if `example_label` equals `value_1` or `value_2`
metricRelabelings:
- sourceLabels: [example_label]
  action: keep
  regex: '(value_1|value_2)'
# Keep metrics only if `example_label_1 = value_1` and `example_label_2 = value_2`
metricRelabelings:
- sourceLabels: [example_label_1, example_label_2]
  separator: ';'
  action: keep
  regex: 'value_1;value_2'
# Keep metrics only if `example_label` exists as a label
metricRelabelings:
- sourceLabels: [example_label_1]
  action: keep
  regex: '.+'

重命名指标 不支持指标重命名。

基本身份验证和持有者令牌

注释

在 Kubernetes 1.37 及更高版本中,Azure Managed Prometheus(或 ama-metrics)对 PodMonitor 和 ServiceMonitor 配置所需的 Kubernetes Secret 采用基于命名空间范围的访问控制。 如果运行的是 Kubernetes 1.37 或更高版本,并且 ServiceMonitor 或 PodMonitor 使用 basicAuth 和引用 Kubernetes 机密的任何配置,则必须配置命名空间范围的机密访问。

Pod/ServiceMonitors 的作用域内机密访问

在 Kubernetes 1.37 及更高版本中,Azure 托管 Prometheus(或 ama-metrics)将对 PodMonitor 和 ServiceMonitor 配置中使用的 Kubernetes Secret 采用命名空间范围内的访问权限。 以前,ama-metrics 组件具有跨群集范围读取所有命名空间的机密的权限。 此更新通过要求对用于基本身份验证的机密进行显式命名空间级访问来提高安全性

更改后:

  • 对机密的访问仅限于显式配置的命名空间
  • 必须在使用机密的每个命名空间中授予基于角色的访问控制(RBAC)权限

Kubernetes 版本的默认行为

早于 1.37 的 Kubernetes 版本

  • 仍启用群集范围的机密访问以实现向后兼容性
  • 按照 此处 的步骤为 ServiceMonitor 和 PodMonitor 配置基本身份验证

Kubernetes 版本 1.37 及更高版本

  • 删除群集范围的机密访问
  • 默认情况下,不会监视机密的命名空间
  • 您必须:
    1. 配置允许的命名空间
    2. 在每个命名空间中添加 RBAC 权限

需要配置此配置时

如果运行的是 Kubernetes 1.37 或更高版本,并且 ServiceMonitor 或 PodMonitor 使用 basicAuth 和引用 Kubernetes 机密的任何配置,则必须配置命名空间范围的机密访问。

为 PodMonitor 和 ServiceMonitor 配置基本身份验证的机密访问

按照以下步骤,使 Azure 托管的 Prometheus 能够安全地读取机密信息。

步骤 1:创建基本身份验证机密

在运行应用程序的命名空间中创建机密:

apiVersion: v1
kind: Secret
metadata:
  name: my-basic-auth
  namespace: my-app          # <-- your application namespace
type: Opaque
data:
  username: <base64-encoded-username>
  password: <base64-encoded-password>

步骤 2:引用 ServiceMonitor/PodMonitor 中的机密

ServiceMonitor 示例:

apiVersion: azmonitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-service-monitor
  namespace: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  endpoints:
    - port: metrics
      basicAuth:
        username:
          name: my-basic-auth    # Secret name from Step 1
          key: username
        password:
          name: my-basic-auth
          key: password

PodMonitor 示例:

apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: my-pod-monitor
  namespace: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  podMetricsEndpoints:
    - port: metrics
      basicAuth:
        username:
          name: my-basic-auth
          key: username
        password:
          name: my-basic-auth
          key: password

步骤 3:配置 secrets_access_namespaces

编辑 ama-metrics-settings-configmap.yaml 以包含机密所在的命名空间::

kind: ConfigMap
apiVersion: v1
metadata:
  name: ama-metrics-settings-configmap
  namespace: kube-system
data:
  prometheus-collector-settings: |-
    cluster_alias = ""
    secrets_access_namespaces = "kube-system,my-app"

注释

  • 使用逗号分隔的命名空间列表
  • 如果也有机密,请包括 kube-system
  • 更改将在 ama-metrics pod 重启后生效

步骤 4:在每个命名空间中创建 RBAC (Kubernetes >= 1.37)

在 Kubernetes >= 1.37 上,ClusterRole 不再授予群集范围的机密访问权限。 必须在Role中列出的RoleBinding命名空间中创建一个secrets_access_namespaces(如有需要,包括kube-system)。 在每个命名空间中应用以下内容。 将 my-app 替换为目标命名空间:

创建角色:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ama-metrics-secrets-reader
  namespace: my-app              # <-- repeat for each namespace
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list", "watch"]

创建 RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ama-metrics-secrets-rolebinding
  namespace: my-app              # <-- repeat for each namespace
subjects:
  - kind: ServiceAccount
    name: ama-metrics-serviceaccount
    namespace: kube-system       # <-- SA lives in kube-system
roleRef:
  kind: Role
  name: ama-metrics-secrets-reader
  apiGroup: rbac.authorization.k8s.io

注释

跨命名空间说明:my-app 中的 RoleBinding 引用了 kube-system 中的 ServiceAccount。 这是有效的 Kubernetes RBAC — RoleBinding 可以从任何命名空间引用主题。

步骤 5:验证

ama-metrics Pod 重启后:

  1. 检查目标分配器日志中是否存在以下情况:
    SecretsAccessNamespaces from configmap: [kube-system my-app]
    
  2. 确认您的 ServiceMonitor/PodMonitor 目标出现在目标分配器的已发现目标中。
  3. 验证抓取结果是否包含来自受基本身份验证保护的端点的指标。

示例:多个命名空间

如果你在my-appbackendmonitoring中存有敏感信息:

  1. ConfigMap 设置:

    secrets_access_namespaces = "kube-system,my-app,backend,monitoring"
    
  2. RBAC(>仅限 1.37):my-appbackendmonitoring 中的每一个里,创建步骤 4 中的 Role + RoleBinding。


故障排除

症状 原因 修复
未发现 ServiceMonitor 目标 目标分配器无法读取的机密 确保命名空间在 secrets_access_namespaces 中,且 Role 和 RoleBinding 存在
forbidden: User "system:serviceaccount:kube-system:ama-metrics-serviceaccount" cannot list resource "secrets" 在 TA 日志中 命名空间中缺少 RBAC 在该命名空间中创建 Role+RoleBinding (步骤 4)
已发现目标,但抓取因 401 而失败 机密存在,但凭据错误 验证机密的 data 字段是否具有正确的 base64 编码值
ConfigMap 更新后设置被忽略 Pod 尚未重启 重启 ama-metrics Pod 以加载新的 ConfigMap 配置值

为 Kubernetes 1.36 及更早版本配置基本身份验证

支持使用 PodMonitor 和 ServiceMonitor 来抓取使用基本身份验证或持有者令牌的目标。 确保包含用户名/密码/令牌的密钥与 pod/服务监视器位于同一命名空间中。 此行为与 OSS prometheus-operator 相同。

基于 TLS 的抓取

如果要从 https 终结点中抓取 Prometheus 指标,Prometheus 配置、PodMonitor 或 ServiceMonitor 应将 scheme 设置为 https 和额外的 TLS 设置。

  1. 在名为 kube-systemama-metrics-mtls-secret 命名空间中创建机密。 在机密对象的数据节中指定的每个键值对都将作为单独的文件装载在此 /etc/prometheus/certs 位置,文件名与数据节中指定的密钥相同。 机密值应经过 base64 编码。

    下面是一个秘密的 YAML 示例:

    apiVersion: v1
    kind: Secret
    metadata:
      name: ama-metrics-mtls-secret
      namespace: kube-system
    type: Opaque
    data:
      <certfile>: base64_cert_content    
      <keyfile>: base64_key_content 
    

    ama-metrics-mtls-secret 机密会挂载到 ama-metrics Pod 上的路径 /etc/prometheus/certs/ 处,并可供 Prometheus 抓取器使用。 密钥将是文件名。 该值经过 base64 解码,并作为容器中文件的内容添加。

  2. 在 Prometheus 配置、PodMonitor 或 ServiceMonitor 中提供文件路径:

    • 使用以下示例为 PodMonitor 或 ServiceMonitor 提供 TLS 配置设置:
     tlsConfig:
       ca:
         secret:
           key: "<certfile>"
           name: "ama-metrics-mtls-secret"
       cert:
         secret:
           key: "<certfile>"
           name: "ama-metrics-mtls-secret"
       keySecret:
           key: "<keyfile>"
           name: "ama-metrics-mtls-secret"
       insecureSkipVerify: false
    

基本身份验证和 TLS

如果要在 CRD 中使用基本身份验证或持有者令牌(基于文件的凭据)和 TLS 身份验证设置,请确保机密 ama-metrics-mtls-secret 包含数据节下的所有密钥及其相应的 base64 编码值,如下所示:

apiVersion: v1
kind: Secret
metadata:
  name: ama-metrics-mtls-secret
  namespace: kube-system
type: Opaque
data:
  certfile: base64_cert_content    # used for TLS
  keyfile: base64_key_content      # used for TLS
  password1: base64-encoded-string # used for basic auth
  password2: base64-encoded-string # used for basic auth

注释

/etc/prometheus/certs/ 路径是必需项,但 password1 可以是任何字符串,并且需要匹配上面创建的机密中的数据对应的密钥。 这是因为机密ama-metrics-mtls-secret被挂载在容器内的路径/etc/prometheus/certs/上。

当机密作为文件装载时,ama-metrics pods 会自动解码 base64 编码值。 确保机密名称是 ama-metrics-mtls-secret 并且在 kube-system 命名空间中。

应首先创建机密,然后在命名空间中创建 kube-system ConfigMap、PodMonitor 或 ServiceMonitor。 机密创建的顺序很重要。 如果没有机密,但 ConfigMap、PodMonitor 或 ServiceMonitor 指向机密,则以下错误将位于 ama-metrics prometheus-collector 容器日志中: no file found for cert....

有关 TLS 配置设置的更多详细信息 ,请参阅tls_config

后续步骤