痛点
Kubernetes 集群规模一上来,成本就成了黑洞。常见问题:
- 无法归因:每月云账单一大坨,根本分不清哪个团队、哪个 Namespace、哪个 Pod 在烧钱
- 资源浪费严重:开发者 request 设 4C8G,实际用了 0.5C1G,节点利用率不到 30%
- Showback/Chargeback 无数据支撑:财务要求按部门分摊成本,运维拿不出精确数据
- 商业方案太贵:Kubecost Enterprise 动辄几万美金/年,中小团队承受不起
OpenCost 是 CNCF 孵化的开源 Kubernetes 成本监控项目(Kubecost 开源核心),能以 Pod 粒度实时计算成本分摊,且完全免费。
方案概述
OpenCost 通过以下机制实现成本可视化:
- 实时资源计量:采集每个 Pod 的 CPU/Memory/GPU/Storage/Network 实际用量
- 云定价 API 集成:自动拉取 AWS/GCP/Azure 的按需定价(支持 Spot/RI/Savings Plans)
- 成本分配模型:按 Namespace、Label、Controller 等维度归因,支持闲置成本再分配
- Prometheus 集成:原生暴露 metrics,可直接对接 Grafana 构建成本大盘
架构图:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Kubernetes │────▶│ OpenCost │────▶│ Prometheus │
│ API Server │ │ (Pod) │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Cloud Cost │ │ Grafana │
│ API (AWS等) │ │ Dashboard │
└──────────────┘ └──────────────┘
实操步骤
Step 1:Helm 部署 OpenCost
前置条件:集群已安装 Prometheus(kube-prometheus-stack 或独立部署均可)。
# 添加 Helm repo
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
# 部署 OpenCost
helm install opencost opencost/opencost \
--namespace opencost --create-namespace \
--set opencost.prometheus.internal.serviceName=prometheus-kube-prometheus-prometheus \
--set opencost.prometheus.internal.namespaceName=monitoring \
--set opencost.ui.enabled=true
关键参数说明:
- prometheus.internal.serviceName:指向你集群中 Prometheus 的 Service 名称
- prometheus.internal.namespaceName:Prometheus 所在 Namespace
- ui.enabled=true:启用内置 Web UI,方便快速查看
验证部署:
kubectl get pods -n opencost
# NAME READY STATUS RESTARTS AGE
# opencost-6f8d7b9c4d-x2k9j 2/2 Running 0 60s
Step 2:配置 AWS 自定义定价(可选但推荐)
默认使用公开按需定价。如果用了 RI 或 Savings Plans,需配置 CUR(Cost and Usage Report)集成:
# values-aws.yaml
opencost:
cloudCost:
enabled: true
exporter:
cloudProviderApiKey: ""
aws:
secret_access_key: "" # 建议用 IRSA
access_key_id: ""
customPricing:
enabled: true
configmapName: opencost-custom-pricing
provider: aws
使用 IRSA(推荐生产环境):
# 创建 IAM 策略
cat > opencost-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cur:DescribeReportDefinitions",
"cur:GetReportData",
"pricing:GetProducts",
"ec2:DescribeInstances",
"ec2:DescribeSpotPriceHistory"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy --policy-name OpenCostPolicy \
--policy-document file://opencost-policy.json
# 绑定 IRSA
eksctl create iamserviceaccount \
--name opencost \
--namespace opencost \
--cluster your-cluster \
--attach-policy-arn arn:aws:iam::123456789:policy/OpenCostPolicy \
--approve
Step 3:Grafana 成本大盘
OpenCost 暴露的核心 Prometheus 指标:
| 指标 | 说明 |
|---|---|
opencost_pod_cpu_cost |
Pod CPU 成本($/h) |
opencost_pod_memory_cost |
Pod 内存成本($/h) |
opencost_pod_network_cost |
Pod 网络成本($/h) |
opencost_namespace_cpu_cost |
Namespace 维度 CPU 成本 |
opencost_cluster_cost_total |
集群总成本 |
Grafana 面板 PromQL 示例 — 按 Namespace 统计日成本 Top10:
topk(10,
sum by (namespace) (
opencost_pod_cpu_cost + opencost_pod_memory_cost
) * 24
)
按 Deployment 统计月度成本:
sum by (controller, namespace) (
(opencost_pod_cpu_cost + opencost_pod_memory_cost + opencost_pod_network_cost) * 720
)
导入社区 Dashboard:Grafana Dashboard ID 18867(OpenCost 官方大盘)。
Step 4:基于成本数据的优化动作
拿到成本数据后,常见优化动作:
# 1. 找出资源严重超配的 Pod(request >> actual)
kubectl top pods -A --sort-by=cpu | head -20
# 2. 通过 OpenCost API 查询过去 7 天 Namespace 成本
curl -s "http://opencost.opencost:9003/allocation/compute?window=7d&aggregate=namespace" | \
jq '.data[] | to_entries[] | {namespace: .key, totalCost: .value.totalCost}' | \
jq -s 'sort_by(-.totalCost) | .[:10]'
# 3. 识别闲置资源(CPU利用率低于 10% 超过 7 天的 Deployment)
# 配合 VPA recommender 调整 request
kubectl get vpa -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}: CPU={.status.recommendation.containerRecommendations[0].target.cpu}, Mem={.status.recommendation.containerRecommendations[0].target.memory}{"\n"}{end}'
避坑指南
1. Prometheus 数据保留期不够导致月度统计失真
问题:默认 Prometheus 保留 15 天,OpenCost 月度成本统计不完整。
解决:
# kube-prometheus-stack values
prometheus:
prometheusSpec:
retention: 32d
# 或者使用 Thanos/Mimir 做长期存储
2. 节点 Spot 实例价格波动大导致成本数据不准
问题:Spot 实例价格每分钟变化,OpenCost 默认拉取频率可能跟不上。
解决:在 Helm values 中调整刷新频率:
opencost:
exporter:
aws:
spotDataRegion: us-east-1
spotDataBucket: your-spot-feed-bucket # 配置 Spot Data Feed
spotRefreshRate: 3600 # 秒
3. Shared Resources(Prometheus、Istio)成本分配争议
问题:基础设施组件(监控、Service Mesh、Ingress Controller)归属哪个团队?
解决:OpenCost 支持 idle cost 和 shared cost 配置:
# 将共享成本按比例分配给所有 Namespace
opencost:
exporter:
defaultIdleCost: "allocated" # 闲置成本按使用量比例分配
sharedNamespaces: "monitoring,istio-system,kube-system"
shareStrategy: "weighted" # 按 CPU/Mem 实际使用量加权
总结
| 维度 | 说明 |
|---|---|
| 部署成本 | 零成本,CNCF 开源项目 |
| 部署复杂度 | Helm 一键装,5 分钟上线 |
| 精度 | Pod 级别实时成本,支持 CPU/Mem/GPU/Network/PV |
| 云厂商支持 | AWS、GCP、Azure、自建(Custom Pricing CSV) |
| 适用规模 | 10~1000+ 节点均可,资源占用极低(~50MB 内存) |
| 对比 Kubecost Enterprise | 功能覆盖 80%,适合中小团队 Showback 场景 |
核心建议:
- 先部署再说:5 分钟部署,立刻看到成本分布,很多浪费一目了然
- 配合 VPA 使用:OpenCost 发现浪费 → VPA 自动调整 Request → 节点数自然下降
- 设置成本告警:当某 Namespace 日成本超阈值,通过 Alertmanager 通知团队
- 按月生成 Chargeback 报告:通过 OpenCost API 导出数据,自动化生成分摊报表
在我的实际经验中,仅通过 OpenCost 发现超配 + VPA 自动调整这一组合拳,就在 200 节点的 EKS 集群上实现了约 25% 的成本削减。关键不在工具,在于让成本对每个团队透明可见 — 当开发者知道自己的服务每月烧了多少钱,行为自然会改变。