mcpField
K
kubesense-slo

kubesense-slo

github.com/kubesense-ai云与 DevOps342 次安装2 天前更新
代码仓库

关于 kubesense-slo

kubesense-slo 是用于创建、预览和诊断 KubeSense 服务级目标的工作流技能。它通过 REST API 管理 SLO,并强调检查实际评估数据,而非只依赖预览结果。

主要功能

  1. 01发现指标、字段和告警渠道
  2. 02构建并预览 SLO 配置
  3. 03创建、读取、更新和删除 SLO
  4. 04检查评估桶与预算消耗
  5. 05配置并验证预算燃尽告警

适用场景

  1. 01为遥测指标创建服务级目标
  2. 02创建前估算合规状态
  3. 03排查 SLO 无数据或预算燃尽
  4. 04迁移或维护现有 SLO

MCP 相关

该技能说明 SLO 没有 MCP 工具,管理操作需通过 `/api/slo` REST API 和 HTTP 调用完成。MCP 查询工具可用于发现指标、字段及相关信息。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kubesense-ai/kubesense-mcp-skills --skill kubesense-slo

安装后在 Claude Code 中输入/kubesense-slo确认已加载。

附带文件references/api-payloads.mdreferences/datadog-migration.md

详细介绍

KubeSense SLO

此处的 SLO 是一份已存储的定义,以及一个后台评估器。每隔 evaluation_interval_seconds,评估器就会对一个时间桶进行评分,将结果写入 ClickHouse,并生成 Prometheus 时间序列(kubesense_slo_*)。合规性则是基于 evaluation_window_days 计算的滚动汇总。

重要

没有 SLO MCP 工具。 日志、链路追踪、指标和告警都有对应工具;SLO 没有。此处所有操作都通过 /api/slo 下的 REST API 完成,认证方式与 MCP 服务完全相同(x-api-key,或 Authorization: Bearer <token>)。使用 MCP 查询工具来发现指标和字段名称,然后构建 SLO 请求体。

因此,这项技能需要 MCP 连接本身无法提供的两样东西:发起 HTTP 调用的方式(带有 curl 的 shell,或 HTTP 工具),以及可放入请求头的 API 凭据值——无法在工具调用中读取 MCP 服务自身的凭据。只有 MCP 的 Agent 仍然可以构建并解释请求载荷,并应明确告知用户需要自行发送。

生命周期

请按顺序执行。第 5 步和第 6 步最容易被跳过,而它们正是发现 SLO 虽然成功存储、却没有评估任何内容的关键步骤。

  1. 发现。 获取真实指标名称(get-available-metrics、get-metric-labels)和真实字段名称(get-trace-or-log-fields)。获取消耗率告警的通道 ID(list-notification-channels)。如果是告警 SLO,还要获取告警规则 UUID。
  2. 构建请求体——包括类型、两个查询、时间窗口和 alert_types。
  3. 使用 POST /api/slo/preview 预览,并了解预览会检查和不会检查的内容。数值明显错误时,通常是筛选条件有问题。no_data 并不能证明筛选有误——真正安静的服务也会产生空时间窗口;修改任何内容前,请先区分这两种情况(见第 6 步)。对于告警 SLO,请明确传入 from_time/to_time:默认时间窗口会回溯到规则创建之前,此时没有触发记录会被视为正常运行时间为 100%。
  4. 使用 POST /api/slo 创建,并保存返回的 ID。没有 ID,就没有 SLO。
  5. 使用 GET /api/slo/{id}?current_time=… 读取并核对,确认存储的配置与发送的内容一致——尤其是 slo_type、operation 和两个 groupBy 列表。
  6. 在一到两个评估间隔后,验证实际时间桶: GET /api/slo/{id}/metrics?from_time=…&to_time=…,并再次读取 SLO。
    • 两次读取之间的 last_evaluated 持续更新,才能证明评估器已处理该 SLO。值为 Null 或停滞不变,说明评估器从未处理它——请检查 status、评估间隔和分组上限。
    • 非零的 total_events(或 total 切片数/秒数)还能证明查询可以解析并且匹配到了数据。
    • 零不一定是问题。 安静的服务会正常产生空时间桶——by_count 的结果是 no_data,time_slice 的结果是正常运行时间。修改 SLO 前,使用 analyze-traces / analyze-logs / analyze-metrics 直接查询相同范围和时间窗口:如果那里也没有记录,说明缺少遥测数据,这是需要在其他地方解决的不同问题。
    • 绝不要扩大用户的筛选范围来让数值出现。 这会改变测量对象,变成没人要求测量的内容。请报告空结果以及你检查过的内容。
  7. 如果设置了 alert_types,请验证生成的告警——它们应作为规则存在,名称为 "<SLO name> Fast Burn Rate" 等,并使用你提供的通道 ID。
  8. 使用 PUT(完整请求体,ID 放在请求体内)更新,或使用 DELETE /api/slo/{id} 删除,然后重复第 5–7 步。更新操作会重新生成对应的规则。

三种 SLI 类型

slo_type分子 / 分母配置项计数单位
by_count良好事件数 / 总事件数两个查询:good_events_filter 和 total_events_filterevents
time_slice良好时间片数 / 总时间片数一个查询(total_events_filter)+ operation + threshold_valueslices
alert未触发秒数 / 总秒数在 total_events_filter.alert_ids 中填写告警规则 IDseconds

省略 slo_type 时,默认值为 by_count。UI 中的名称分别是“按计数”“按时间片”和“按正常运行时间”。

路由

用户询问……执行此操作
“为 X 创建一个 SLO”构造 POST /api/slo 请求体 — references/api-payloads.md
“这个 SLO 能达标吗?”/“合规情况会如何?”创建前先调用 POST /api/slo/preview — 无需付费,也不会存储任何内容;但这只是估算,并非重放(限制)
“我们有哪些 SLO / 哪些已违约?”调用 POST /api/slo/list?status=active&current_time=…,或 POST /api/slo/stats
“这个 SLO 为什么在消耗预算?”调用 GET /api/slo/{id}/burn-rate/timeseries,然后使用相同的筛选条件查询 kubesense-traces / kubesense-logs
“预算消耗时提醒我”在 SLO 上设置 alert_types — 不要手动编写燃烧率告警规则
“迁移我们的 Datadog SLO”references/datadog-migration.md
“在仪表板上显示 SLO”kubesense-dashboards — panelType: "slo"

端点

所有端点均位于 /api/slo 下,RBAC 模块为 slo。创建、更新和删除操作还需要该模块的写入权限。

方法路径用途
POST/api/slo创建 — 在 data 中返回新 SLO 的 ID
PUT/api/slo更新 — ID 应作为请求体中的 id 传入,而非放在路径中
DELETE/api/slo/{id}软删除(设置 removed),并移除其燃烧率告警规则
GET/api/slo/{id}?current_time=<RFC3339>获取单个 SLO 及其汇总数据
POST/api/slo/list?status=active&current_time=<RFC3339>列表;筛选条件放在 JSON 请求体中
GET/api/slo/search?search=<substr>&limit=50仅返回 {id, name} — 用于选择器
POST/api/slo/stats按状态统计数量:normal / warning / breached / no_data
POST/api/slo/preview对某个时间窗口执行合规性试运行,不存储任何内容(状态为 normal/breached/no_data — 永远不会是 warning)
GET/api/slo/{id}/metrics?from_time=&to_time=获取某个时间窗口的良好 / 不良 / 总量及预算
GET/api/slo/{id}/groups?windows=last_24_hour,last_7_days获取各分组的数据,一次扫描多个时间窗口
GET/api/slo/{id}/timeseries随时间变化的合规情况
GET/api/slo/{id}/burn-rate/timeseries随时间变化的燃烧率
POST/api/slo/filters, /api/slo/filter/search获取列表页的筛选值

警告

/list 和 GET /{id} 必须提供 current_time,且 /list 必须提供 status。两者都是查询参数,而非请求体字段。省略 current_time 会导致调用返回 500 错误(“currentTime must not be zero”);省略 status 时,WHERE status = ? 将无法匹配任何内容,结果会是空列表,看起来就像“没有 SLO”。请传入 status=active。

创建负载

基于 traces 的最小可行 by_count SLO:

{
  "name": "Checkout availability",
  "description": "Successful checkout spans / all checkout spans",
  "slo_type": "by_count",
  "metric": "requests",
  "slo_target_percentage": 99.9,
  "evaluation_window_days": 30,
  "evaluation_time_interval_seconds": 60,
  "evaluate_from": "2026-09-01T00:00:00Z",
  "evaluation_start_time": "2026-09-01T00:00:00Z",
  "status": "active",
  "cluster": "", "namespace": "", "workload": "", "customer_identifier": "",
  "operation": "", "threshold_value": 0, "value": 0,
  "good_events_filter":  { "selectedMode": "traces", "value_operation": "row_count", "groupBy": [], "unified_filter": { "type": "common", "common_filter": [ {"field": "app_service", "operation": "IN", "values": ["checkout"]}, {"field": "status", "operation": "IN", "values": ["ok"]} ], "adv_filters": {} } },
  "total_events_filter": { "selectedMode": "traces", "value_operation": "row_count", "groupBy": [], "unified_filter": { "type": "common", "common_filter": [ {"field": "app_service", "operation": "IN", "values": ["checkout"]} ], "adv_filters": {} } },
  "alert_types": ["burn_rate_fast", "error_budget_low"],
  "notification_channels": [1]
}

每种类型的结构、metrics 和 logs 变体,以及响应正文,都在 references/api-payloads.md 中。

正文规则:

  • evaluation_time_interval_seconds 必须 > 0 — 服务端会直接拒绝 0,评估器也会跳过间隔为 0 的 SLO,避免无限循环。
  • status: "active",否则评估器不会选取它。
  • slo_target_percentage 是百分比(99.9),不是小数。
  • 设置 warning_target_percentage 时,应当高于目标值 — 这样才能在违约前发出警告。UI 会强制要求 >= target + 0.1;API 完全不会验证此值,低于目标值的值会被存储,但永远不会达到,因为会先检查是否已违约。
  • metric 是一个标签,不是查询。traces SLI 使用 "requests",metrics SLI 使用 PromQL 指标名称,alert SLI 使用 "alert_uptime"。系统不会根据它执行任何计算 — 它只会显示在列表页和筛选条件中。
  • operation / threshold_value 仅适用于 time_slice 条件。by_count 会忽略它们;应将延迟阈值作为时长筛选条件并入 good 查询。
  • 更新是完整替换:PUT /api/slo 会根据正文写入每一列,因此请发送完整对象(先用 GET /api/slo/{id} 读取),并在正文中设置 id。

Good 和 Total 是 Alert 查询配置

good_events_filter 和 total_events_filter 是 alert 规则使用的同一种 query_config 对象 — JSON 键、执行器和字段允许列表都相同。这是最有用的一点:任何关于构建 alert 规则查询的知识都适用于此处。

键含义
selectedModetraces | logs | metrics。为空时默认为 traces。
unified_filtertraces/logs 筛选树:{type, common_filter[], adv_filters{}}
promql仅用于 metrics — 完整的 metrics 查询。(alert 规则的 queryMode 在此处没有对应字段,因此会被丢弃。)
value_operationrow_count(通常选择此项)、unique_count、avg、sum、min、max、百分位数
fields任何非计数型 value_operation 都必需
groupBy[{field, type, is_attribute}] — 参见分组。
alert_ids仅用于 alert 类型的 SLO

重要

字段名称遵循 ALERT 引擎的词汇,而不是查询工具的词汇。 Logs 和 traces SLI 查询会通过 alert 规则使用的同一套规则引擎执行器运行,因此应使用 app_service(而不是 service)、level(而不是 type)、pod_name/pod、node_name/node、return_code/status_code。完整的允许列表见 kubesense-alerts — 这些字段同样适用于 SLO。

还有一点差异需要注意:POST /api/slo/preview 会通过 API 自身的 explore 引擎运行查询,而评估器会通过规则引擎运行查询。 两者的字段映射有重叠,但并不完全一致,因此某个名称可能在预览中正常,但每次评估时仍然报错。预览还会对 traces 和 logs 强制使用 row_count(忽略 value_operation 和 fields,因此延迟 SLI 预览的实际上是请求数),并且对 metrics 只采样约 300 个数据点,而不是评估每个 bucket。预览可以捕获筛选条件为空或错误的情况,但不会验证数值。创建后,请在第一个真实 bucket 上确认。

公式和比率

由多个查询和类似 (A/B)*100 的表达式构建的 Datadog 监控器或 SLO,无法作为一个整体迁移。迁移目标决定了它的形式:

要迁移的内容迁移到哪里方式
SLI 为分子 / 分母的 SLOby_count SLO两个查询,不使用公式。 A → good_events_filter,B → total_events_filter。评估器会自行计算两者的比值。
对比率设置阈值的监控器告警规则告警支持真正的公式模式——将 A、B 和 expression 保留为独立查询,并将 metric_query_label 指向公式的标签。参见 kubesense-alerts。
每个时间间隔都将比率与阈值比较的 SLItime_slice SLO一个内联的 PromQL,搭配 operation + threshold_value。
临时分析,不涉及 SLO 或规则analyze-telemetry (MCP)一组带标签的查询,加上 {"selectedMode": "formula", "expression": "(A/B)*100"} — 可组合日志、追踪和指标。

警告

selectedMode: "formula" 在 SLO 中不起作用。 评估器通过一个执行器工厂解析查询;该工厂支持 logs、metrics 和 traces,其他类型都会返回 unsupported query type: formula——每次评估都会如此,因此 SLO 会永远停留在 no_data。告警支持公式;SLO 不支持。

改为将其内联为一个 PromQL 字符串。 产品本身就是这样处理的:SLO 编辑器的公式构建器会在提交前,将每个标签替换为其括号括起的查询,并存储为一个扁平的 promql。因此,(A/B)*100 会存储为

(sum(increase(http_requests_total{status=~"5.."}[5m])) / sum(increase(http_requests_total[5m]))) * 100

重要

不要将比率内联到 by_count SLO 中。 在那里,比率 就是 SLO——评估器会计算 good/total,并据此构建错误预算。如果将百分比作为 total_events_filter 输入,它会把百分比计为事件,后续所有数值都将毫无意义。比率应放在 time_slice(每个切片一个值,与阈值比较)或告警规则中。

对内联比率进行分组时,除法的两侧都要保留 by (…),并且查询中的 groupBy 不能留空——仅使用 by (…) 会让 SLO 仍走单序列路径(参见“分组”)。

分组

在 total_events_filter 上设置 groupBy(并在 good_events_filter 上设置匹配项),SLO 就会按组拆分为各自的合规性数值,并按组标识进行合并。

  • 每个 kubesense_slo_* 序列都会以 Prometheus 标签的形式输出各组,此外还会输出一个标记为 slo_group="*" 的汇总整体序列。
  • slo_id、slo_group、window、target_percentage、error_budget 和 __name__ 是保留字段——如果某个 groupBy 字段最终生成了这些名称之一,就会被丢弃。按 workload、namespace 或 cluster 分组没有问题,这正是将它们加入序列的方式。
  • 字段名称会转换为有效的 Prometheus 标签名称:[a-zA-Z0-9_] 以外的字符都会变成 _,因此 service.name → service_name。
  • 最多只能有 100 个组。 超过此数量时,评估器会跳过整个存储桶并记录日志——SLO 会悄无声息地停止生成数据。切勿按 pod、instance、trace_id 或任何基数不受限的字段分组。
  • 良好侧中没有匹配总量组的组会被截断,并发出警告。两个 groupBy 列表必须完全一致。
  • 指标 SLI 也需要非空的 groupBy。 PromQL 中的 by (…) 本身不会启用分组:评估器读取的是 total_events_filter.groupBy;如果列表为空,多序列结果会被缩减为第一个序列,其余序列会被静默丢弃。(指标上的 time_slice 是例外——它始终以多序列方式运行。)参见 references/api-payloads.md。

燃烧率告警由 alert_types 生成

设置 alert_types 后,API 会在与 SLO 相同的事务中为你创建告警规则:

alert_types 值规则严重级别
burn_rate_fastkubesense_slo_burn_rate{window="1h"} 超过 (days × 24 × 0.02) / 1严重
burn_rate_slowkubesense_slo_burn_rate{window="6h"} 超过 (days × 24 × 0.05) / 6警告
error_budget_criticalkubesense_slo_error_budget_balance < 5严重
error_budget_lowkubesense_slo_error_budget_balance < 10警告

阈值根据 evaluation_window_days 推导,因此 30 天的窗口会得到熟悉的 14.4× / 6× 多窗口燃烧率。每次更新时都会重新计算。

警告

切勿手动编写这些规则。 PUT /api/slo 会删除附加到该 SLO 的所有告警规则,并根据 alert_types 重建它们;DELETE 会将它们删除。 对生成的规则进行的编辑会在下一次 SLO 更新时被静默还原。

“附加”指的是规则自身的 labels.slo_id,而不是其 PromQL。删除操作使用 WHERE JSON_EXTRACT(labels, '$.slo_id') = <id>,不会检查规则是谁创建的。因此,查询中仅选择 kubesense_slo_burn_rate{slo_id="…"} 的手写规则会保留;但如果规则自身的标签中带有 slo_id——复制生成的规则时显而易见的做法——就会和它们一起被删除。若要保留规则,请勿在其标签中添加 slo_id。

SLO 上的 notification_channels 决定这些生成的规则会向哪些渠道发送告警。请先调用 list-notification-channels(MCP)或 GET /api/alerts/notification-channels——如果 ID 不存在,规则创建就会失败,并导致整个创建事务回滚。

窗口、频率与回填

  • evaluation_window_days 是滚动合规窗口(7、30、90 等)。
  • evaluation_time_interval_seconds 是时间桶大小;对于 time_slice,也是切片大小。UI 为切片提供 60 和 300 这两个选项,与 Datadog 提供的两个值相同。
  • evaluate_from 是评估的起始位置,评估器会从这里开始,以每轮 20 个时间桶的批次回填至当前时间。若将其设为几个月前且间隔为 60s,在追上实时数据前就意味着需要处理数万个时间桶——请将其设为你实际关心的窗口起点。
  • 如果 evaluation_start_time 早于 evaluate_from,就会被向后调整为 evaluate_from。
  • UI 和 /groups 展示的汇总数据:last_2_hour、last_24_hour、last_7_days、last_28_days。

陷阱

陷阱后果
evaluation_time_interval_seconds: 0创建时返回 500;现有值为 0 时,评估器会跳过该 SLO
status 不是 "active"已存储、会出现在列表中,但永远不会被评估
/list 未指定 status=active列表为空,看起来像是“没有 SLO”
/list 或 GET /{id} 未指定 current_time返回 500
未指定 selectedMode会被静默视为 traces——仅设置了 promql 的指标 SLI 会查询 traces,结果一无所获
在 unified_filter 中使用查询工具的字段名(service、type)每次评估都会出错;SLO 会停留在 no_data
groupBy 解析出的分组数 > 100所有时间桶都会被跳过——没有数据,也不会在 UI 中显示错误
好事件和总事件的 groupBy 列表不同多出的好事件分组会被截断;这些分组的合规率会显示为 100%
未设置 alert_ids 的告警 SLO评估器会跳过它(否则它会永远报告完美的 100%)
warning_target_percentage 低于目标值永远不会发出警告——警告阈值必须高于目标值
time_slice 的 operation 使用长格式(less_than)或小写(lt)通过 API 验证,但评估器无法识别——每个时间片都会被判定为停机,永远是 0%。仅支持大写的 GT/GTE/LT/LTE/EQ
time_slice 的 operation: "NEQ"创建时会被拒绝,尽管 UI 下拉菜单提供了此选项
Metrics by_count 使用 by (…),但 groupBy 为空只会统计第一个序列;其余序列会被静默忽略
手写规则自身的标签中包含 slo_id下次 PUT /api/slo 时,该规则会和生成的规则一起被删除
evaluate_from 早于规则创建时间的告警 SLO会回填虚构的完美可用时间——不会记录为无数据
编辑生成的消耗率规则下次 PUT /api/slo 时会被还原
使用不完整的请求体执行 PUT完整替换——未发送的字段会被写入其零值
evaluation_window_days 不是 7 的倍数且大于 31(例如 90)通过 API 可以正常使用,但 UI 的周期输入框(1–31 × 天/周)无法表示该值,因此之后在 UI 中编辑会验证失败

不同类型的缺失数据语义不同——这是有意设计的

  • by_count:分母为空时为 no_data。不会计算合规率,也不会对该时间桶评分。
  • time_slice:缺失数据计为正常运行时间,与 Datadog 一致。计数查询返回 0 时会被视为“无数据”,因此零流量分钟属于正常时间片。这意味着遥测中断也会显示为健康的 SLO。
  • alert:停机时间是指定规则触发区间的并集;如果规则在窗口边界仍处于触发状态,则会计为持续触发,直至该边界。完全没有触发记录的时间桶会被评为完全健康,而不是无数据——因此,早于规则创建时间的 evaluate_from 会向预算中回填虚构的完美可用时间。请将 evaluate_from 设为规则开始存在的时间。

交接 SLO 时,请说明适用哪一种。这是“这个数值看起来不对”的最常见原因。

错误预算和消耗率

  • error_budget_percentage = 100 - slo_target_percentage。
  • error_budget_balance = (1 - error% / budget%) × 100,不设上下限——预算超支时会变成负数(实际值为 99.52%、目标值为 99.9% 时为 −380%),与 Datadog 一致。不要“修正”负数;它反映的正是预算消耗情况。
  • 消耗率经过归一化:无论窗口长度如何,1.0 都表示恰好消耗整个窗口的预算。列表页指示器使用 2h 窗口,超过 6 为严重,超过 1 为升高——与 Datadog 显示的阈值相同。
  • 输出的序列:kubesense_slo_evaluated_events_total / _good、kubesense_slo_evaluated_events_bad_percent、kubesense_slo_error_budget_balance、kubesense_slo_burn_rate(窗口为 1h、2h、6h)、kubesense_slo_breached、kubesense_slo_status、kubesense_slo_burn_rate_status。使用 kubesense-metrics 查询这些序列。

规则

  1. 首先发现真实的指标和字段名称(get-available-metrics、 get-trace-or-log-fields)。绝不要臆造名称。
  2. 在 unified_filter 中使用告警引擎的字段词汇——用 app_service, 而不是 service;用 level,而不是 type。
  3. 创建前务必先执行 POST /api/slo/preview,并向用户展示返回的合规性和预算数值。预览免费,且不会存储任何内容。
  4. 在两个筛选器上都显式设置 selectedMode。默认值是 traces。
  5. 始终确保 evaluation_time_interval_seconds > 0 且 status: "active"。
  6. good 和 total 的 groupBy 必须相同,并将分组数限制在远低于 100 组;即使是指标 SLI 也要设置它,因为仅使用 by (…) 会让你得到一个序列。
  7. 绝不要手写燃烧率告警规则——使用 alert_types,并先确认通道 ID 存在。
  8. PUT 会发送整个对象;编辑前先读取 SLO。
  9. time_slice 运算符必须为大写的 GT、GTE、LT、LTE、EQ。其他写法都无法端到端生效。
  10. 说明你所构建类型的缺失数据语义——对于告警 SLO,还要将 evaluate_from 设为其规则开始存在的时间。
  11. 除非 POST /api/slo 返回了 ID,否则绝不要声称 SLO 已创建;在真实数据桶返回事件(步骤 6)之前,也绝不要称其正常工作。

评论

支持 Markdown