跳转至

第九节 通过kube-state-metrics添加CRD状态指标

在 Kubernetes 中,自定义资源(CRD)是一种扩展 API 的机制,可以使用 Kubernetes APIServer 来存储和管理自定义对象。

本文我们将描述如何在不编写自定义资源注册表和自己构建 KSM 的情况下,根据自定义资源的状态来添加指标。

配置

需要下面描述的 YAML 配置文件来定义你的自定义资源和要转换为指标的字段。

有两个参数需要用到:

  • --custom-resource-state-config 在内联的 yaml 中
  • --custom-resource-state-config-file 指定的配置文件路径

如果提供了两个标志,则内联配置将优先。

当同一资源存在多个条目时,kube-state-metrics 将退出并报错,这包括引用不同 API 版本的配置

除了指定 --custom-resource-state-config* 标志之外,还应该将复数形式的自定义资源种类添加到 --resources 标志中的暴露资源列表中

如果不指定 --resources,那么 kube-state-metrics 将考虑在 --custom-resource-state-config* 中配置的所有已知自定义资源和所有可用的默认 kubernetes 对象。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-state-metrics
  namespace: kube-system
spec:
  template:
    spec:
      containers:
      - name: kube-state-metrics
        args:
          - --custom-resource-state-config
          -  |  # 在YAML文件中,| 允许将多行字符串作为标志值传递  # https://yaml-multiline.info
              spec:
                resources:
                  - groupVersionKind:
                      group: myteam.io
                      version: "v1"
                      kind: Foo
                    metrics:
                      - name: active_count
                        help: "Count of active Foo"
                        each:
                          type: Gauge
                          ...
          - --resources=certificatesigningrequests,configmaps,cronjobs,daemonsets,deployments,endpoints,foos,horizontalpodautoscalers,ingresses,jobs,limitranges,mutatingwebhookconfigurations,namespaces,networkpolicies,nodes,persistentvolumeclaims,persistentvolumes,poddisruptionbudgets,pods,replicasets,replicationcontrollers,resourcequotas,secrets,services,statefulsets,storageclasses,validatingwebhookconfigurations,volumeattachments,verticalpodautoscalers

也可以将 kube-state-metrics 配置为仅在自定义资源模式下运行,除了指定 --custom-resource-state-config* 标志之外,还可以将 --custom-resource-state-only 设置为 true。

使用此配置,kube-state-metrics 只会考虑在 --custom-resource-state-config* 中配置的已知自定义资源。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-state-metrics
  namespace: kube-system
spec:
  template:
    spec:
      containers:
      - name: kube-state-metrics
        args:
          - --custom-resource-state-config
          -  |
              spec:
                resources:
                  - groupVersionKind:
                      group: myteam.io
                      version: "v1"
                      kind: Foo
                    metrics:
                      - name: active_count
                        help: "Count of active Foo"
                        each:
                          type: Gauge
                          ...
          - --custom-resource-state-only=true

注意:customresource_groupcustomresource_versioncustomresource_kind 这几个公共标签是保留的,将被 groupVersionKind字段中的值覆盖。

示例

下面我们将将使用以下自定义资源来进行说明:

kind: Foo
apiVersion: myteam.io/vl
metadata:
    annotations:
        bar: baz
        qux: quxx
    labels:
        foo: bar
    name: foo
spec:
    version: v1.2.3
    order:
        - id: 1
          value: true
        - id: 3
          value: false
    replicas: 1
status:
    phase: Pending
    active:
        type-a: 1
        type-b: 3
    conditions:
        - name: a
          value: 45
        - name: b
          value: 66
    sub:
        type-a:
            active: 1
            ready: 2
        type-b:
            active: 3
            ready: 4
    uptime: 43.21

单值

配置如下:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind:
        group: myteam.io
        kind: "Foo"
        version: "v1"
      metrics:
        - name: "uptime"
          help: "Foo uptime"
          each:
            type: Gauge
            gauge:
              path: [status, uptime]

使用上面的配置会产生如下所示指标:

kube_customresource_uptime{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1"} 43.21

多指标

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind:
        group: myteam.io
        kind: "Foo"
        version: "v1"
      commonLabels:   # labels can be added to all metrics from a resource
        crd_type: "foo"
      labelsFromPath:  # 来自 path 路径的标签
        name: [metadata, name]  # 相当于:name=metadata.name
      metrics:
        - name: "ready_count"
          help: "Number Foo Bars ready"
          each:
            type: Gauge
            gauge:
              # 以对象或数组为目标将生成每个元素标签 FromPath 的指标,并且值与此路径相关
              path: [status, sub]

              # 如果 path 目标是一个对象,则对象的 key 将会被用作标签值
              # StateSet 类型不支持这一点,因为所有值都是true,这是多余的。
              labelFromKey: type
              # 可以解析特定于此路径的标签值
              labelsFromPath:
                active: [active]
              # 要用作指标值的实际字段,应为数字、布尔值或 RFC3339 时间戳字符串。
              valueFrom: [ready]
          commonLabels:
            custom_metric: "yes"
          labelsFromPath:
            # 整个对象可以通过前缀“*”复制到标签中
            # *任何内容都将被复制到标签中,首先是排序最高的 * 字符串
            "*": [metadata, labels]
            "**": [metadata, annotations]

            # 或者可以复制特定字段。这些字段将始终覆盖*s中的值
            name: [metadata, name]
            foo: [metadata, labels, foo]

然后会产生如下所示的指标:

kube_customresource_ready_count{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", active="1",custom_metric="yes",foo="bar",name="foo",bar="baz",qux="quxx",type="type-a"} 2
kube_customresource_ready_count{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", active="3",custom_metric="yes",foo="bar",name="foo",bar="baz",qux="quxx",type="type-b"} 4

指标类型

该配置支持 OpenMetrics 规范 中的三种指标。指标类型由 type 字段及其在类型特定结构中的特定配置指定。

Gauge

Gauge 是表示的是当前的测量值,如当前使用的内存字节数或队列中的项目数,对于 gauge 来说,绝对值是大家感兴趣的东西。例如:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind:
        group: myteam.io
        kind: "Foo"
        version: "v1"
      metrics:
        - name: "uptime"
          help: "Foo uptime"
          each:
            type: Gauge
            gauge:
              path: [status, uptime]  # status.uptime

使用上面的配置可以产生如下所示的指标:

kube_customresource_uptime{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1"} 43.21

不过需要注意下类型转换。Gauge 生成 float64 类型的值,但自定义资源可以是各种类型,kube-state-metrics 对很多类型执行隐式类型转换,支持的类型包括:

  • (u)int32/64、int、float32 和 byte 转换为 float64
  • 如果 NilIsZero 为真,nil 一般会被映射为 0.0,否则会产生一个错误
  • bool 类型 true 映射到 1.0,false 映射到 0.0
  • 对于字符串,以下逻辑适用:
    • "true" 和 "yes" 被映射为 1.0,"false" 和 "no"被映射为 0.0(全部不区分大小写)
    • RFC3339 时间被解析为浮点时间戳
    • 最后使用 https://pkg.go.dev/strconv#ParseFloat 将字符串解析为浮点数,它应该支持所有常见的数字格式,如果失败,则会产生错误

Kubernetes 控制器上的状态条件示例:

kind: CustomResourceStateMetrics
spec:
  resources:
  - groupVersionKind:
      group: myteam.io
      kind: "Foo"
      version: "v1"
    labelsFromPath:
      name:
      - metadata
      - name
      namespace:
      - metadata
      - namespace
    metrics:
    - name: "foo_status"
      help: "status condition "
      each:
        type: Gauge
        gauge:
          path: [status, conditions]
          labelsFromPath:
            type: ["type"]
          valueFrom: ["status"]

这适用于根据 kubernetes api (https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Condition) 公开状态条件的 kubernetes 控制器 CR:

status:
  conditions:
    - lastTransitionTime: "2019-10-22T16:29:31Z"
      status: "True"
      type: Ready

可以产生如下所示的指标:

kube_customresource_foo_status{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", type="Ready"} 1.0

StateSet

StateSet 表示一系列相关的布尔值,也称为 bitset。如果需要对 ENUM 进行编码,则可以通过 StateSet 来完成。例如:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind:
        group: myteam.io
        kind: "Foo"
        version: "v1"
      metrics:
        - name: "status_phase"
          help: "Foo status_phase"
          each:
            type: StateSet
            stateSet:
              labelName: phase
              path: [status, phase]
              list: [Pending, Bar, Baz]

StateSet 类型的指标将为每个资源的列表中定义的每个值生成一个指标,如果该值与列表中的值匹配,则该值将为 1。会生成如下所示的指标:

kube_customresource_status_phase{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", phase="Pending"} 1
kube_customresource_status_phase{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", phase="Bar"} 0
kube_customresource_status_phase{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", phase="Baz"} 0

Info

Info 指标用于暴露文本信息,这些信息在进程生命周期内不应更改,常见示例是应用程序的版本、修订控制提交和编译器的版本。 Info 类型的指标的值始终为 1,例如:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind:
        group: myteam.io
        kind: "Foo"
        version: "v1"
      metrics:
        - name: "version"
          help: "Foo version"
          each:
            type: Info
            info:
              labelsFromPath:
                version: [spec, version]

会产生如下所示的指标:

kube_customresource_version{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1", version="v1.2.3"} 1

命名

默认指标名称带有前缀以避免与其他指标冲突。默认情况下,使用 kube_ 的指标前缀与自定义资源的 group+version+kind连接,你可以使用 metricNamePrefix 字段覆盖此行为。

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind: ...
      metricNamePrefix: myteam_foos
      metrics:
        - name: uptime
          ...

会产生如下所示的指标:

myteam_foos_uptime{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1"} 43.21

要完全省略命名空间空间和/或子系统,请将它们设置为空字符串:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind: ...
      metricNamePrefix: ""
      metrics:
        - name: uptime
          ...

会产生如下的指标:

uptime{customresource_group="myteam.io", customresource_kind="Foo", customresource_version="v1"} 43.21

日志

如果已注册指标路径但未在自定义资源上找到,则会记录错误日志。对于某些资源,这可能会产生大量无用的日志数据,可以使用资源或指标上的 errorLogV 设置指标或资源的错误日志详细程度:

kind: CustomResourceStateMetrics
spec:
  resources:
    - groupVersionKind: ...
      errorLogV: 0  # 0 = default for errors
      metrics:
        - name: uptime
          errorLogV: 10  # only log at high verbosity

路径语法

Path 路径被指定为字符串列表,每个字符串都是一个 path 片段,根据自定义资源的数据动态解析。如果缺少 path 的任何部分,则结果为零。例如:

# 简单路径查找
[spec, replicas]                         # spec.replicas == 1

# 数组索引
[spec, order, "0", value]                # spec.order[0].value = true

# 通过 key = value 在列表中查找元素
[status, conditions, "[name=a]", value]  # status.conditions[0].value = 45

# 如果要匹配的值是数字或布尔值,则将该值作为数字或布尔值进行比较
[status, conditions, "[value=66]", name]  # status.conditions[1].name = "b"