如何定义自定义成本模型

本指南展示了如何通过定义自定义成本模型来添加新的计费项。工作流程包括四个部分:

  • 准备使用指标
  • 准备标签指标
  • 为成本管理智能体添加采集配置
  • 为成本管理服务器添加展示配置

作为具体示例,我们将添加两个 GPU 计费项:GPU 计算核数(cores)和 GPU 内存,并启用按标签定价。

目录

准备使用指标

使用指标表示需要计费的消耗。提供一个 PromQL 查询,用于按步长(例如 5 分钟)聚合使用量。每个步长产生一个数据点,表示前一时间窗口内的使用量;最终使用量是所选时间范围内的总和。

Prometheus 指标类型包括 Counter、Gauge、Summary 和 Histogram。对于使用量,应使用 Counter 或 Gauge。示例:

# Counter 示例(例如 GPU 核心使用时间):
vgpu_core_usage_seconds_total{"containeridx":"0","deviceuuid":"GPU-2eec4202-80dc-870f-3ca5-25879d96eca7","endpoint":"monitor","instance":"10.3.0.130:9395","ip":"192.168.131.32","job":"hami-scheduler","namespace":"kube-system","node_name":"192.168.131.32","nodename":"192.168.133.48","pod":"hami-scheduler-86b7ff47c6-sp7kb","podname":"pytorch-cuda12-1-57d9ff4544-bqkvg","podnamespace":"yulin-2","service":"hami-scheduler","zone":"vGPU"}

# 对应的使用查询(步长 = 5 分钟):
sum by (deviceuuid, podnamespace) (rate(vgpu_core_usage_seconds_total{}[5m]))


# Gauge 示例(例如 GPU 内存使用字节数):
vgpu_memory_usage_bytes{"containeridx":"0","deviceuuid":"GPU-2eec4202-80dc-870f-3ca5-25879d96eca7","endpoint":"monitor","instance":"10.3.0.130:9395","ip":"192.168.131.32","job":"hami-scheduler","namespace":"kube-system","node_name":"192.168.131.32","nodename":"192.168.133.48","pod":"hami-scheduler-86b7ff47c6-sp7kb","podname":"pytorch-cuda12-1-57d9ff4544-bqkvg","podnamespace":"yulin-2","service":"hami-scheduler","zone":"vGPU"}

# 对应的使用查询(步长 = 5 分钟):
sum by (deviceuuid, podnamespace) (avg_over_time(vgpu_memory_usage_bytes{}[5m]))

准备标签指标

标签指标为使用量附加属性,以便可以按标签定价。它们必须能与使用指标进行关联——至少共享一个标签(例如 deviceuuid)——这样系统才能用这些属性丰富使用数据。

标签指标使用 Gauge。示例:

# 标签指标(标签字段在此示例中以 label_ 开头):
vgpu_device_labels{"deviceuuid":"GPU-2eec4202-80dc-870f-3ca5-25879d96eca7","label_device":"nvidia","label_modelName":"Tesla T4","podnamespace":"yulin-1"}

# 标签指标查询:
vgpu_device_labels{}

# 使用查询与标签查询的关系(GPU 核心和内存示例):
# 1) 使用查询按 (deviceuuid, podnamespace) 分组,每个序列包含 deviceuuid
# 2) 标签查询按自身标签分组,每个序列包含 deviceuuid
# 3) 因为两者都包含唯一的 deviceuuid,标签查询中的标签可以附加到使用数据上

添加采集配置(成本管理智能体)

在每个运行成本管理智能体的集群中创建 ConfigMap,用于声明需要采集的内容。

一个典型的采集记录(GPU 核心/内存)映射到配置字段示例如下:

{
    "id": "cab9881e380fcf72726ccf45565ffc2d",           # 根据约定字段自动生成
    "kind": "Vgpu",                                     # 与配置中的 kind 一致
    "name": "GPU-2eec4202-80dc-870f-3ca5-25879d96eca7", # 来自 usage.mappers.name
    "namespace": "cpaas-system",                        # 来自 usage.mappers.namespace
    "cluster": "default-cluster",                       # 智能体运行的集群
    "project": "cpaas-system",                          # 从 namespace 推导
    "labels": {                                          # 如果配置了 labels.query,则来自标签查询
        "key1": "val1",
        "key2": "val2"
    },
    "date": "2024-04-29T00:00:00Z",                     # 当天起始时间
    "period": "hourly",                                 # 与配置中的 period 一致
    "start": "2024-04-29T00:05:00Z",                    # 期间起始时间
    "end": "2024-04-29T00:59:59Z",                      # 期间结束时间
    "category": "VgpuCore",                             # 与配置中的 category 一致
    "item": "VgpuCoreUsed",                             # 与配置中的 item 一致
    "usage": 200                                         # 来自使用查询结果
}

现在为智能体创建 ConfigMap(GPU 核心和内存):

apiVersion: v1
data:
  config: |
    - kind: Vgpu                                        # 必填;必须与服务器配置一致
      category: VgpuCore                                # 必填;必须与服务器配置一致
      item: VgpuCoreUsed                                # 必填且唯一;必须匹配服务器配置
      period: Hourly                                    # 必填;Hourly 或 Daily,推荐 Hourly
      labels:                                           # 可选;通过此查询为使用量添加标签
        query: "vgpu_core_labels{}"                     # 例如,添加 GPU 型号、厂商标签
        mappers:
          name: deviceuuid                              # 将 deviceuuid 映射为 name
          namespace: podnamespace                       # 将 podnamespace 映射为 namespace
          cluster: ""                                   # 为空时自动填充当前集群
          project: ""                                   # 为空时自动从 namespace 填充项目
      usage:                                            # 必填;使用查询(按 deviceuuid,podnamespace 分组)
        query: "sum by (deviceuuid, podnamespace) (rate(vgpu_core_usage_seconds_total{}[5m]))"
        step: 5m                                        # 必填;采样步长
        mappers:
          name: deviceuuid                              # 将 deviceuuid 映射为 name
          namespace: podnamespace                       # 将 podnamespace 映射为 namespace
          cluster: ""                                   # 为空时自动填充
          project: ""                                   # 为空时自动填充
    - kind: Vgpu                                        # 第二个计费项
      category: VgpuMemory                              # 必须与服务器配置一致
      item: VgpuMemoryUsed                              # 唯一的 item 名称
      period: Hourly
      labels:
        query: "vgpu_core_labels{}"
        mappers:
          name: deviceuuid
          namespace: podnamespace
          cluster: ""
          project: ""
      usage:
        query: "sum by (deviceuuid, podnamespace) (avg_over_time(vgpu_memory_usage_bytes{}[5m]))"
        step: 5m
        mappers:
          name: deviceuuid
          namespace: podnamespace
          cluster: ""
          project: ""
kind: ConfigMap
metadata:
  labels:
    cpaas.io/slark.collection.config: "true"            # 必填;启用采集配置
  name: slark-agent-project-config-vgpu
  namespace: cpaas-system                               # 必填;

添加 yaml 后,需要重启智能体 Pod 以重新加载配置。

kubectl delete pods -n cpaas-system -l service_name=slark-agent

添加展示/存储配置(成本管理服务器)

在运行成本管理服务器的集群中创建 ConfigMap,用于声明计费项、计费方法、单位和展示名称。此配置告诉服务器计费内容及方式。

apiVersion: v1
data:
  config: |
    - name: VgpuCore                                     # 计费项名称;必须与上述 category 匹配
      displayname:
        zh: "Vgpu"
        en: "Vgpu"
      methods:                                           # 计费方法列表(唯一名称)
        - name: Usage                                    # 方法名称
          displayname:
            zh: "使用量"
            en: "Used Usage"
          item: VgpuCoreUsed                             # 必须匹配智能体配置中的 item
          divisor: 1000                                  # 单位换算(例如 mCPU 转核数)
          unit:
            zh: "core-hours"
            en: "core-hours"
    - name: VgpuMemory                                   # 第二个计费项
      displayname:
        zh: "Vgpu 显存"
        en: "VgpuMemory"
      methods:
        - name: Used
          displayname:
            zh: "使用量"
            en: "Used Usage"
          item: VgpuMemoryUsed
          divisor: 1073741824                            # 字节 -> Gi
          unit:
            zh: "Gi-hours"
            en: "Gi-hours"
kind: ConfigMap
metadata:
  labels:
    cpaas.io/slark.display.config: "true"                # 必填;启用展示/存储配置
  name: slark-display-config-for-vgpu
  namespace: kube-public                                 # 必填;

添加 yaml 后,需要重启服务器 Pod 以重新加载配置。

kubectl delete pods -n cpaas-system -l service_name=slark-server

注意事项与最佳实践

  • 保持智能体和服务器配置中的命名一致:kindcategoryitem 必须匹配。
  • 推荐使用 Hourly 以获得更细粒度和更快反馈。
  • 确保标签指标能通过共享标签(例如 deviceuuid)与使用指标关联。
  • 在上线前本地验证 PromQL 查询;监控初始运行的数据合理性。
  • 从少量集群和计费项开始,验证后再逐步扩展。