使用 BigQuery 账单查询模板分析 GKE 集群与工作负载成本
【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills
本篇技术指南以gke-cost-analysis技能中的 BigQuery 账单查询模板为核心,讲解如何基于 GCP Billing Detailed BigQuery Export(gcp_billing_export_resource_v1_*)回答 GKE 成本问题。读完本文,你将掌握三类可直接复用的bq query模板:单集群单工作负载成本、每个集群中每个工作负载的成本分解、集群内按命名空间的成本分解,并理解 GKE Cost Allocation 标签体系、Credits 与折扣的语义,以及如何从成本分析平滑过渡到成本优化。
数据基础:GKE 成本从何而来
GKE 成本数据的权威来源是GCP Billing Detailed BigQuery Export,其表名通常形如gcp_billing_export_resource_v1_*。要查询这类表,用户必须提供完整的 BigQuery 表路径(包含数据集名、表名以及对应 Billing Account ID 的表路径),该前提在 gke-cost-analysis/SKILL.md 的 "Key Points & Pricing Drivers" 一节中被明确强调。
另一个关键前提是GKE Cost Allocation 必须启用。只有集群开启了--enable-cost-allocation,BigQuery 账单导出中才会填充goog-k8s-cluster-name、k8s-namespace、k8s-workload-name、k8s-workload-type等标签,按命名空间、标签和工作负载级别进行计费粒度切分。如果查询返回的标签为空,就需要先通过以下命令在集群上启用成本分配(注意:这是修改集群的操作,不是只读命令,运行前需获得用户明确确认,且标签只从启用时刻起开始填充,不会对历史数据回溯补全):
gcloud container clusters update {cluster_name} \ --enable-cost-allocation \ --region {region}理解计费模式对解读查询结果同样重要:
- Autopilot 模式:直接按 Pod 的资源请求(
requests.cpu、requests.memory、临时存储)计费。请求超配的 Pod 无论是否真正使用这些 CPU 或内存,都会推高账单。 - Standard 模式:按已置备的节点池虚拟机(如
e2、n4、c3等)计费,空闲节点或多个低利用率的开发集群会产生额外基础设施成本。 - 集群管理费:Standard 和 Autopilot 模式均按约
$0.10/小时收取,免费额度会对每个结算账号下的一个符合条件集群免除该费用。
模板使用规则:占位符、默认值与 SQL 语法
billing-queries.md中的三个模板遵循统一的占位符与默认值约定:
占位符策略:所有参数({billing_export_table}、{project_id}、{region}、{cluster_name}、{namespace}、{workload_type}、{workload_name})必须替换为用户提供的实际值。用户必须提供完整的账单导出表路径(包含 Billing Account ID 的数据集名和表名)。
默认值(除非用户另行指定):
- 时间范围:最近 30 天(
_PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)) - 行数限制:10 行
- 排序方式:按成本降序(
ORDER BY cost DESC)
语法注意:
- 优先使用 BigQuery CLI:
bq query --nouse_legacy_sql(即标准 SQL,禁用旧版 SQL)。 - 在标准 SQL 中,项目 ID 与数据集之间使用点号(
.)分隔,而非冒号:{project_id}.{dataset_name}.{table_name}。
模板一:查询单集群中单个工作负载的成本
当需要回答"某个集群里某个命名空间下某个工作负载花了多少钱"这类问题时,使用该模板。它通过五层EXISTS标签过滤将账单数据精确收敛到单一工作负载,同时分别计算计入 Credits 后的实际成本与Credits 前的毛成本:
bq query --nouse_legacy_sql ' SELECT SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS cost, SUM(cost) AS cost_before_credits FROM {billing_export_table} AS bqe WHERE _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY) AND project.id = "{project_id}" AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-location" AND l.value = "{region}") AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-name" AND l.value = "{cluster_name}") AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "k8s-namespace" AND l.value = "{namespace}") AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "k8s-workload-type" AND l.value = "{workload_type}") AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "k8s-workload-name" AND l.value = "{workload_name}") ; '关键字段解读:
project.id:账单条目所属的 GCP 项目 ID,用于限定项目范围。goog-k8s-cluster-location/goog-k8s-cluster-name:GKE Cost Allocation 写入的集群位置与集群名标签。k8s-namespace/k8s-workload-type/k8s-workload-name:命名空间、工作负载类型(如 Deployment、StatefulSet、Job 等)与工作负载名称标签。cost列:SUM(cost)与 credits 金额之和,是扣除抵扣后的实际净成本。cost_before_credits列:仅SUM(cost),不含 credits,用于观察抵扣前毛成本。
模板二:查询每个集群中每个工作负载的成本
该模板用于全景式盘点,按项目、集群位置、集群名、命名空间、工作负载类型、工作负载名称六个维度分组,输出各工作负载的净成本与毛成本,并按成本降序取前 10 条。WHERE子句中仅要求goog-k8s-cluster-name标签存在即可,这样能将整体账单数据精确限定到 GKE 成本范围:
bq query --nouse_legacy_sql ' SELECT project.id AS project_id, (SELECT l.value FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-location" LIMIT 1) AS cluster_location, (SELECT l.value FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-name" LIMIT 1) AS cluster_name, (SELECT l.value FROM bqe.labels AS l WHERE l.key = "k8s-namespace" LIMIT 1) AS k8s_namespace, (SELECT l.value FROM bqe.labels AS l WHERE l.key = "k8s-workload-type" LIMIT 1) AS k8s_workload_type, (SELECT l.value FROM bqe.labels AS l WHERE l.key = "k8s-workload-name" LIMIT 1) AS k8s_workload_name, SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS cost, SUM(cost) AS cost_before_credits FROM {billing_export_table} AS bqe WHERE _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY) AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-name") GROUP BY 1, 2, 3, 4, 5, 6 ORDER BY 7 DESC LIMIT 10 ; '实现细节说明:
- 标签取值的标量子查询:由于账单导出的
labels是STRUCT数组,这里通过(SELECT l.value FROM bqe.labels AS l WHERE l.key = "..." LIMIT 1)以标量子查询方式取出对应标签的值,供外层GROUP BY分组。 - 分组与排序:
GROUP BY 1, 2, 3, 4, 5, 6按 SELECT 列表中的前六列分组;ORDER BY 7 DESC按第七列(净成本cost)降序排序,配合LIMIT 10输出成本最高的前十个工作负载——这正好回答了"哪个项目 / 哪个集群 / 哪个工作负载最贵"这类问题。
模板三:查询集群内按命名空间的成本分解
该模板聚焦单一集群({project_id}+{cluster_name}),按命名空间聚合净成本与毛成本,用于回答"集群里哪个命名空间最烧钱":
bq query --nouse_legacy_sql ' SELECT (SELECT l.value FROM bqe.labels AS l WHERE l.key = "k8s-namespace" LIMIT 1) AS k8s_namespace, SUM(cost) + SUM(IFNULL((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0)) AS net_cost, SUM(cost) AS gross_cost FROM {billing_export_table} AS bqe WHERE _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY) AND project.id = "{project_id}" AND EXISTS(SELECT * FROM bqe.labels AS l WHERE l.key = "goog-k8s-cluster-name" AND l.value = "{cluster_name}") GROUP BY 1 ORDER BY 2 DESC LIMIT 10 ; '注意:与模板二不同,这里将goog-k8s-cluster-name的EXISTS过滤条件与具体集群值(AND l.value = "{cluster_name}")绑定,从而把查询范围严格限定在指定集群内。正如文档注释所强调的,检查goog-k8s-cluster-name标签是否存在,可以将总账单数据精确限定到 GKE 成本。
解读查询结果:Credits 与折扣语义
三个模板都同时输出cost(净成本)与cost_before_credits/gross_cost(毛成本)两套口径,这是分析账单时非常关键的一环:
- Committed Use Discounts(CUD)和Spot 虚拟机在账单导出中体现为 credits(抵扣项)或折扣费率条目。
- 净成本(
cost)反映计入这些抵扣后的真实支出;毛成本(cost_before_credits)反映抵扣前的计费金额。 - 两者差值越大,说明该工作负载/命名空间享受的折扣力度越大;两者接近则说明该部分开销几乎全部按原价计费。分析时可以据此判断成本优化空间,相关说明同样见于 gke-cost-analysis/SKILL.md 的 "Credits & Discounts Impact" 一节。
结合实时监控诊断成本驱动因素
SQL 模板解决的是历史成本归因,而要定位"为什么贵",还需要把历史账单与实时资源利用率对照。gke-cost-analysis技能提供了三条只读 CLI 命令(参见 gke-cost-analysis/SKILL.md 的 "Live Cluster & Cost Monitoring" 一节):
# 查看某个结算账号的预算(需要 Cost Management API) gcloud billing budgets list --billing-account={billing_account} --quiet # 查看集群节点的实时资源利用率 kubectl top nodes # 查看各命名空间下 Pod 的资源用量(与 requests 对照以诊断超配浪费) kubectl top pods --all-namespaces --containers典型诊断路径是:先用模板二/模板三从 BigQuery 中找出成本最高的集群或命名空间,再用kubectl top对比实际利用率与已请求的资源量——如果 Pod 请求量远高于实际用量,即使该 Pod 没有真正消耗 CPU 或内存,Autopilot 计费依然按请求量收取,这就锁定了主要的成本驱动因素。
从成本分析走向成本优化
gke-cost-analysis只负责分析,不负责变更。当分析出优化空间后,实施层面(如配置 VPA 推荐模式、将 CPU/内存调整为P95 * 1.2、通过nodeSelector或ComputeClass配置 Spot 虚拟机、强制ResourceQuotas、选择机型与 CUD 等)应移交至gke-cost-optimization技能处理,两者分工明确(见 gke-cost-optimization/SKILL.md):先启用成本分配并完成诊断分析,再应用优化工作流。
相关资源
- 模板原文:billing-queries.md
- 技能完整说明(计费模式、Credits 语义、实时监控命令、Cost Allocation 启用警告):gke-cost-analysis/SKILL.md
- 成本优化技能(VPA/MPA 建议模式、Spot 虚拟机、资源配额等落地手段):gke-cost-optimization/SKILL.md
【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考