OpenCost
OpenCost is an open-source cost monitor for Kubernetes. It reads CPU, memory, GPU, storage and network data from Prometheus, prices each resource with cloud rates or a custom price sheet, and charges each container the greater of its request and its usage, then rolls the result up by namespace, label, workload or cluster. Apache 2.0, a CNCF incubating project, free to run; the only cost is the Prometheus it needs. It fits any cluster where the question is which team or product takes which share of the hardware.
OpenCost is a cost monitor for Kubernetes clusters. It answers a question that the cloud bill and kubectl top cannot answer alone: how much of the cluster each namespace, workload or label uses, in money. It combines resource metrics from Prometheus with a price for each resource, and it shows the result in a web UI, a REST API and as Prometheus metrics.
What it is
OpenCost has two parts. The first is a vendor-neutral specification for Kubernetes cost allocation: what an asset is, how a workload is charged, and how idle and shared costs are calculated. The second is a Go implementation of that specification, plus a separate web UI (opencost/opencost-ui).
- Origin and governance. Kubecost developed OpenCost and released it as open source. The CNCF accepted it on 17 June 2022 and moved it to the Incubating maturity level on 25 October 2024 (CNCF project page).
- Licence. Apache 2.0. There is no paid edition of OpenCost itself.
- Release line. The current line is v1.121.x. v1.121.3 shipped on 16 September 2026 with GCP GPU pricing and IBM Cloud usage reports. The official Helm chart (2.5.33 at the time of writing) has
appVersion: 1.121.3. - Pricing sources. OpenCost reads on-demand and spot prices from AWS, Azure and GCP (and from smaller providers such as OVH and STACKIT, added in the 1.120 line). For on-premises clusters it uses a custom price sheet.
- Recent changes to note before an upgrade. v1.120.3 added auth middleware and reads provider configuration from
cloud-integration.json. It also made the built-in MCP server opt-in. v1.121.0 deactivates the write endpoints unless an admin token is set (PR #3910).
How it works
OpenCost does not collect metrics itself. It runs Prometheus queries. Prometheus scrapes cAdvisor (container usage), kube-state-metrics or OpenCost's own emitted equivalents (requests, pods, nodes), and the OpenCost exporter's pricing metrics. The OpenCost server then builds two things from those series:
- Assets. Nodes, persistent volumes, disks, load balancers and network traffic, each with an hourly cost. When a provider gives only a bundled node price, OpenCost splits it across CPU, GPU and RAM with a fixed ratio of their base prices.
- Allocations. Each container is charged max(request, usage) for CPU, memory and GPU, because the scheduler reserves the request whether the container uses it or not. Storage is charged on the PVC request size. Container costs then roll up to pods, controllers, namespaces, labels or clusters.
The asset cost that no workload takes becomes idle cost (asset costs − workload costs). A query can return idle as a separate __idle__ row, or share it across the workloads. System namespaces and overhead can be shared in the same way: evenly, in proportion to cost, or by a custom metric.
Step 1 of 4. The exporter loads hourly rates for CPU, RAM, GPU and storage from the provider API or from the custom pricing ConfigMap.
Two paths: the collection loop that feeds Prometheus, and an allocation query from the UI or API.
The same numbers are also exported back as Prometheus metrics, so Grafana dashboards and alert rules can use cost without a call to the OpenCost API.
When to use it
Reach for it when:
- Several teams, products or tenants share one cluster and each needs a fair share of the bill (showback or chargeback).
- You want to see over-provisioning: requests that are much larger than usage show up as low efficiency and high idle cost.
- The cluster runs on owned hardware and you want a consistent per-namespace share, even if the dollar figure is notional.
- Prometheus is already in the cluster, so the extra cost is one small Deployment.
Skip it when:
- One workload owns the whole cluster. The node bill is already the answer.
- You need invoice-grade billing reconciled to the cent. Cloud billing exports (for example AWS CUR) are the source of truth; OpenCost can read them, but the allocation is still a model.
- There is no Prometheus and you do not want to run one.
At a glance
Core concepts
- Asset — a thing that costs money in the cluster: node, disk, PV, load balancer, network egress.
- Allocation — the share of asset cost charged to a container, rolled up to any Kubernetes grouping.
- max(request, usage) — the charge rule for CPU, memory and GPU. A pod in
ImagePullBackOffis not charged. - Idle — asset cost that no workload took. Can be reported per cluster or per node (
idleByNode=true). - Shared cost — cost from system namespaces, idle or overhead, spread across tenants by a chosen rule.
- Window / step / aggregate — the three main query parameters: the time range, the size of each set inside it, and the grouping key.
Key facts
| Aspect | Value |
|---|---|
| Licence | Apache 2.0 |
| Governance | CNCF Incubating (since October 2024) |
| Current release | v1.121.3 |
| Kubernetes | 1.21 or later |
| Hard dependency | Prometheus (or a Prometheus-compatible query endpoint such as Thanos) |
| Install | Helm chart opencost-charts/opencost |
| Ports | UI 9090, API 9003, MCP server 8081 |
| Pricing | AWS, Azure, GCP and others; custom price sheet for on-premises |
| Default daily retention | 15 days (dailyResolutionDays) |
OpenCost compared with Kubecost
| Aspect | OpenCost | Kubecost |
|---|---|---|
| Licence | Apache 2.0, CNCF | Commercial product, free tier |
| Origin | Open-sourced by Kubecost | The commercial product from the same original team |
| Multi-cluster view | One deployment per cluster; a shared backend needs label filters | Built-in aggregation across clusters in paid tiers |
| Support | Community (CNCF Slack, GitHub issues) | Vendor support |
| Fit | One team, a homelab, or a small platform | Organisations that want a supported product |
How to integrate
Install with Helm and point it at the existing Prometheus. The example below is for a kube-prometheus-stack release in the monitoring namespace:
helm repo add opencost-charts https://opencost.github.io/opencost-helm-chart
helm repo update
helm install opencost opencost-charts/opencost \
--namespace opencost --create-namespace -f values.yaml
# values.yaml
opencost:
exporter:
defaultClusterId: prod # shows in every allocation row
prometheus:
internal:
enabled: true
namespaceName: monitoring
serviceName: prometheus-kube-prometheus-prometheus
port: 9090
mcp:
enabled: false # chart default is true; opt in on purpose
customPricing: # owned hardware: set your own rates
enabled: true
provider: custom
costModel:
description: On-premises rates
CPU: 1.25
RAM: 0.50
storage: 0.25
ui:
enabled: true
metrics:
serviceMonitor:
enabled: true
additionalLabels:
release: prometheus # must match the Prometheus selector
When several clusters write to one shared backend, each OpenCost deployment must filter on the cluster label (multi-cluster guide):
opencost:
exporter:
extraEnv:
CURRENT_CLUSTER_ID_FILTER_ENABLED: "true"
PROM_CLUSTER_ID_LABEL: "cluster"
CLUSTER_ID: "prod" # must equal the label value on the series
Check the install with a port-forward and one API call:
kubectl -n opencost port-forward service/opencost 9003 9090
curl -s 'http://localhost:9003/allocation/compute?window=7d&aggregate=namespace&includeIdle=true'
In the GL stack
OpenCost 1.121.3 runs on the beta and the prod clusters, the two K3s clusters that serve paiddaily.io, sagedaily.io, builddaily.io and the other products. The management cluster does not run it.
- Data source. OpenCost allocates CPU and memory cost per namespace and per workload from the Prometheus data that the monitoring stack already collects. It adds no new collector.
- What the number means. The clusters run as VMs on owned hardware, so there is no cloud bill to split and the dollar figure is notional. The useful output is the share: which product takes how much of the CPU and memory that the hardware provides.
Gotchas
- Prometheus agent mode cannot answer queries. OpenCost runs PromQL against its source. A Prometheus in agent mode only scrapes and remote-writes, so OpenCost must query the server that stores the data, or a Thanos-style query endpoint.
- Shared backends mix clusters. With one central store, OpenCost reports every cluster's series unless
CURRENT_CLUSTER_ID_FILTER_ENABLED,PROM_CLUSTER_ID_LABELandCLUSTER_IDall match the real cluster label. The docs list a wrong label key and a mismatchedCLUSTER_IDas the common mistakes. - Duplicate metrics with kube-state-metrics. OpenCost can emit KSM-style metrics itself. If KSM also runs, check
emitKsmV1MetricsandemitKsmV1MetricsOnlyso that the same series is not counted from two sources. - The MCP setting differs between binary and chart. Since v1.120 the binary keeps the MCP server off by default, but the Helm chart's
opencost.mcp.enableddefaults totrueon port 8081. Set it explicitly and do not expose it without auth. - Write endpoints need an admin token since v1.121.0. Calls such as
POST /serviceKeyand cloud configuration endpoints are off untilopencost.exporter.adminTokenis set. UseexistingSecret, not an inlinevalue. - Custom price units are not stated in the on-prem docs. Compare the values with the shipped
default.json(based on GCP us-central1) before trusting absolute numbers. Relative shares stay correct either way. - Requests drive cost. A pod that requests 2 CPU and uses 0.1 is charged for 2. Low efficiency in the report usually points to requests, not to OpenCost.
Risks
- Model, not invoice. The allocation rules are a choice. Two tools with different idle and shared-cost rules give different numbers for the same cluster.
- Project health. The project ships releases about monthly and passed CNCF incubation review in 2024. It came from one company, Kubecost, so its direction is tied in part to that commercial product.
- Prometheus coupling. Retention, scrape gaps and label changes in Prometheus show up directly as gaps or errors in cost data.
- Exposure. The UI, API and MCP server have no sign-in by default. Keep them cluster-internal or put them behind an authenticating proxy.
Alternatives
- Kubecost — the commercial product from the team that open-sourced OpenCost. Pick it when a vendor-supported product and a single multi-cluster view matter more than a free licence.
- Cloud provider allocation — for example AWS split cost allocation data for EKS. Pick it when the cluster is managed and the cloud bill is the only source of truth that finance accepts.
- Grafana dashboards on kube-state-metrics — request and usage panels per namespace with a fixed rate multiplier. Pick it when a rough share is enough and another service is not wanted.
Related
- Prometheus and Grafana — the data OpenCost reads and the dashboards that can show its exported cost metrics.
- K3s and Lima — the clusters and VMs whose hardware is being shared out.
- Argo CD — the GitOps delivery for the beta and prod clusters.
- Alertmanager and Pyrra — alerting and SLOs on the same Prometheus data.
- Official: OpenCost docs, opencost/opencost releases, OpenCost specification, Helm chart, CNCF project page.
