Flexera 2023年云状态报告显示,成熟工程组织的非生产环境(non-prod)占总云支出的30%–40%。这个数字放在任何一家年云支出千万级的公司,都意味着每年有三到四百万美元在staging、dev、test环境里空转。但绝大多数团队对这些环境零可见性:没有成本追踪,没有闲置检测,没有问责机制。
问题不是缺工具。Prometheus和Grafana你早就有了。缺的是把成本数据接进工程师每天早上都会看的那个仪表盘。
本文展示如何构建一个Grafana仪表盘,同时展示环境健康状态(CPU、内存、Pod状态)和实时美元成本,按命名空间、按环境、按小时拆分。当工程师打开staging仪表盘,看到"这个集群今天花了89美元,利用率4%",他们会行动。
现状:三个窗口,零交集
理解非生产环境的现状需要同时打开至少三个东西:云计费控制台看成本,Grafana看性能,kubectl或Lens看Pod状态。这些工具互不通信。
AWS Cost Explorer里的成本数据延迟24–48小时。Grafana展示实时利用率,但没有美元上下文。非生产命名空间在两者中都很少出现。
结果是没人知道非生产环境实时花了多少钱。闲置集群在夜间、周末、节假日持续运行。不是因为工程师不在乎,而是因为触发行动的反馈信号根本不存在。
我们要构建的架构把这三个窗口压缩成一个Grafana仪表盘,后端用Prometheus。
数据源:你已经有了,只是没连起来
成本仪表盘运行在两个你可能已有的数据源上:kube-state-metrics和cAdvisor(随kubelet捆绑)。
kube-state-metrics暴露超过100个Kubernetes对象指标:Pod阶段、容器资源请求和限制、节点可分配容量。cAdvisor提供实时CPU和内存消耗。
两者都不直接暴露美元成本。这需要一条recording rule(记录规则),从第一性原理计算每命名空间的小时成本。
从kube-state-metrics需要的关键指标:
kube_pod_container_resource_requests{resource="cpu"} — 容器的CPU请求
kube_node_status_allocatable{resource="cpu"} — 节点的可分配CPU
kube_node_labels{label_node_kubernetes_io_instance_type} — 节点实例类型,用于映射到价格
cAdvisor提供:
container_cpu_usage_seconds_total — 实际CPU使用率,用于计算利用率百分比
container_memory_working_set_bytes — 实际内存使用
价格数据需要静态配置。AWS、GCP、Azure的按需价格不会实时变化,可以硬编码为ConfigMap或简单的JSON文件,由Prometheus通过file_sd_configs加载。
核心公式:容器成本 = 资源占比 × 节点价格
Recording rule是非谈判项。原始PromQL跨所有Pod和节点的成本计算很慢,仪表盘刷新需要2–4秒。Recording rule每5分钟预计算小时成本,查询时间降至50毫秒以下。
我们使用的成本分配模型源自OpenCost规范,适配按需定价。核心思想:容器成本等于其请求占节点资源的比例,乘以节点小时价格。
CPU公式:
container_hourly_cost_cpu = (cpu_request / node_allocatable_cpu) × node_hourly_price
内存同理,用内存单位。容器总成本取资源约束中的绑定项:CPU和内存分配比例的最大值。这防止多租户节点上的重复计算。
以AWS us-east-1区域运行t3.large实例的8节点staging集群为例:
t3.large按需价格:$0.0832/小时
节点可分配CPU:2 vCPU
节点可分配内存:8 GiB
集群小时成本:8 × $0.0832 = $0.6656
一个请求0.5 vCPU、2 GiB内存的容器:
CPU占比:0.5 / 2 = 25%
内存占比:2 / 8 = 25%
取最大值25%,小时成本:$0.6656 × 25% = $0.1664
Prometheus recording rule生成cost_per_namespace_hour指标:
预聚合在namespace层级,而非单个容器。工程师关心的是"staging-api命名空间花了多少钱",不是某个特定Pod。
仪表盘设计:一个屏幕,两种语言
仪表盘顶部是成本卡片:今日总成本、本周趋势、预算使用率(如果配置了软预算)。
中间是热力图:命名空间 × 小时,颜色深浅表示成本高低。一眼看出哪些命名空间在夜间持续烧钱。
底部是利用率散点图:横轴CPU利用率,纵轴内存利用率,气泡大小表示成本。右下角的肥大气泡 = 高成本低利用率 = 优化目标。
关键交互:点击任意命名空间,下钻到该环境的详细视图。显示该命名空间下的所有Deployment,每个的CPU请求vs实际使用、内存请求vs实际使用、小时成本。
这个下钻视图暴露了一个常见反模式:请求设置过高。某服务请求4 vCPU但实际使用0.3,Grafana会显示"请求成本$1.33/小时,实际使用成本$0.10/小时",浪费率93%。
工程师看到数字后会自己调整。不需要成本优化团队发邮件,不需要FinOps工具生成报告。反馈循环压缩到同一个屏幕内。
Recording Rule 实战:从慢查询到50毫秒
原始PromQL计算namespace成本看起来像这样:
sum by (namespace) (
kube_pod_container_resource_requests{resource="cpu"}
* on(node) group_left
(node_hourly_price / kube_node_status_allocatable{resource="cpu"})
这条查询在1000+ Pod的集群上执行需要2–4秒。每次仪表盘刷新都卡一下,工程师会关掉这个面板。
Recording rule改成每5分钟预计算:
groups:
- name: cost
interval: 5m
rules:
- record: namespace:container_cpu_cost_per_hour:sum
expr: |
sum by (namespace, node) (
kube_pod_container_resource_requests{resource="cpu"}
* on(node) group_left
(node_hourly_price / kube_node_status_allocatable{resource="cpu"})
仪表盘查询简化为:
sum by (namespace) (namespace:container_cpu_cost_per_hour:sum)
查询时间:50毫秒。工程师无感知刷新。
价格数据:静态配置,动态加载
云厂商价格不会每小时变,但实例类型会新增。我们把AWS价格表做成ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: cloud-pricing
data:
aws_us_east_1.json: |
"t3.micro": 0.0104,
"t3.small": 0.0208,
"t3.medium": 0.0416,
"t3.large": 0.0832
Prometheus通过file_sd_configs加载,配合relabel规则把实例类型映射到价格指标:
relabel_configs:
- source_labels: [__meta_kubernetes_node_label_node_kubernetes_io_instance_type]
target_label: instance_type
recording rule里用lookup把instance_type转成node_hourly_price。
价格更新频率?每月一次足够。AWS降价通知会提前30天发出,有充足时间更新ConfigMap。
利用率计算:请求 vs 实际
成本只算请求(request)会低估,只算实际使用(usage)会掩盖配置问题。我们展示两者。
请求成本:基于resource_requests,代表"承诺支出",即集群必须预留的资源。
实际成本:基于cAdvisor的usage数据,按节点价格比例折算,代表"真实消耗"。
两者比值定义效率分数:
efficiency_score = actual_cost / request_cost
分数接近1 = 请求设置合理。分数低于0.3 = 严重过度配置,优化空间巨大。
这个分数直接显示在仪表盘上,按命名空间排序。工程师打开页面,看到自己负责的命名空间效率分数0.15,会主动排查。
多环境策略:staging、dev、test差异化
不同非生产环境有不同的成本容忍度和优化策略。
Staging:需要24/7运行,但利用率可以低。重点监控"是否有人在用",通过活跃Deployment数量判断。零活跃Deployment连续4小时 = 自动缩容候选。
Dev:个人开发环境,下班后应该归零。设置硬预算:单个命名空间日成本上限$20,超限时告警并建议销毁。
Test:CI/CD触发,按需启动。重点监控"启动到就绪"时间,以及测试完成后是否及时清理。遗留Pod是主要成本泄漏点。
仪表盘用变量切换环境,每个环境有独立的recording rule集合和告警阈值。
告警设计:从被动响应到主动干预
成本告警容易变成噪音。我们设置三层:
信息层:日成本超过周均值150%,发送到Slack成本频道。不打扰,只记录。
警告层:单个命名空间连续6小时零利用率但持续产生成本,@channel提及。暗示配置错误或遗忘的环境。
行动层:dev环境日成本超$50且效率分数低于0.2,自动创建Jira工单并分配命名空间所有者。工单包含Grafana链接和优化建议。
关键:告警里嵌入仪表盘深链。工程师点击直接跳到问题命名空间,不需要手动导航。
实施路径:从0到1的四周计划
第一周:部署kube-state-metrics和cAdvisor(如果还没有),验证指标采集。
第二周:构建价格ConfigMap,编写核心recording rule,验证成本计算与AWS账单误差在5%以内。
第三周:搭建基础仪表盘,邀请2-3个团队试用,收集反馈。
第四周:全量推广,配置告警,建立命名空间所有权映射(成本归因需要知道谁负责)。
常见陷阱:
Spot实例价格波动的处理。如果集群混用按需和Spot,需要分别计算。Spot价格变化快,建议用AWS的Spot价格API每小时更新,或保守估计按按需价格的30%折算。
预留实例(RI)和节省计划(Savings Plans)的摊销。如果组织购买了RI,实际成本低于按需价格。需要与财务团队对齐:仪表盘展示"摊销成本"还是"按需等价成本"?前者反映真实支出,后者反映优化机会。
共享节点的成本归属。系统Pod(kube-system、monitoring)的成本按什么比例分摊?建议单独标记为"平台成本",不归因到业务命名空间。
效果验证:数字说话
某中型SaaS公司实施此方案后的数据:
实施前:非生产环境占云支出38%,利用率中位数12%,成本可见性延迟48小时。
实施后6个月:非生产环境占比降至22%,利用率中位数提升至31%,实时成本可见性。
关键行为改变:工程师开始在下班前检查仪表盘,主动销毁闲置环境。周五下午的成本曲线从平坦(持续运行)变成阶梯状(批量清理)。
一个意外发现:测试环境的"启动-测试-清理"周期中,清理阶段的失败率被长期忽视。成本仪表盘暴露了遗留Pod的累积效应,推动CI/CD流水线修复了清理逻辑。
扩展:从成本到碳排
云厂商开始提供碳排放数据。AWS在2023年底推出Customer Carbon Footprint Tool,延迟同样24–48小时。
同样的架构可以扩展:把碳排放因子(kg CO2e / kWh)加入价格ConfigMap,recording rule计算namespace_hourly_carbon。
仪表盘增加"碳成本"面板。对25-40岁的工程师群体,这个数字有时比美元更有驱动力。
实施复杂度:碳排放数据的地域差异比价格更大。us-east-1和eu-west-1的电网清洁度不同,需要按区域配置。
替代方案对比:为什么不直接用OpenCost/Kubecost
OpenCost是开源成本监控工具,Kubecost是其商业版。两者都提供namespace级成本拆分,为什么不直接用?
OpenCost需要单独部署,增加组件运维负担。它的数据模型与Prometheus不完全兼容,导出到Grafana需要额外适配。
更重要的是:工程师的屏幕时间有限。多一个工具 = 多一个标签页 = 更低的查看频率。把成本数据塞进现有的Grafana仪表盘,利用的是已经建立的习惯,而非创造新习惯。
Kubecost的商业功能(预算告警、优化建议)确实更完善。但基础版本的功能——namespace成本拆分、利用率关联——完全可以用原生Prometheus + Grafana实现,零额外许可成本。
选择取决于组织成熟度。已经有强FinOps团队、预算充足的公司,Kubecost的ROI明确。工程文化偏向"自己造"、对 vendor lock-in 敏感的组织,本文方案更可持续。
维护成本:不是一次性项目
价格ConfigMap需要月度更新。新实例类型上线时,未配置价格的节点会显示为"unknown",需要人工介入。
Recording rule的评估性能需要监控。集群规模增长10倍后,5分钟评估间隔可能不够,需要调整到2分钟或增加Prometheus资源。
命名空间所有权映射会腐烂。工程师转岗、项目重组后,成本归因到错误的人,告警会被忽略。建议季度审计,与IAM权限审查同步进行。
仪表盘本身的迭代:工程师会提出新需求——按Deployment拆分、按团队聚合、与CI/CD构建号关联。预留20%时间持续优化。
一个未被讨论的问题
成本可见性提升后,有些工程师会过度优化。把请求压到极限,节省几美元,但增加了生产环境OOM(内存溢出)的风险。
需要在团队层面建立规范:非生产环境的请求可以激进,但生产环境保留安全边际。成本仪表盘上标记环境类型,避免误读。
另一个边界:个人开发环境的隐私。成本数据可能暴露某工程师"这周只写了100行代码但环境跑了50小时"。数据访问权限需要设计:工程师看自己的命名空间,经理看团队汇总,财务看全局。
某公司在实施后发现,dev环境的成本分布高度不均:20%的命名空间占80%成本。深入调查后发现,部分工程师把dev环境当"个人服务器"跑长期任务。这不是技术问题,是政策问题。成本仪表盘暴露了现象,解决方案需要HR介入。
热门跟贴