For DevOps engineers and developers, Kubernetes is great for abstracting infrastructure. It lets us focus on building and shipping applications without worrying whether it’s an m6i.large or a t3.medium that’s currently running under the hood. Out of sight, out of mind.
But as of 2025, most companies consider K8s costs a major concern, so the expectations on those managing the infrastructure (us, unfortunately) to mitigate and account for those costs are higher than ever. Yet how can we be accountable for something we literally don’t see? As long as we can’t break K8s workloads down by pod, namespace, or team, there’s no way to just point to a specific app or workload and say, this one is costing us the most.
So, what do we do? How can we gain accurate visibility into our K8s clusters and make everyone’s lives (especially ours) easier?
Let’s break it down.
Why It’s So Hard to Track Kubernetes Costs
Kubernetes is a great orchestrator, but it’s not designed for cost clarity.
- Pods move around. One pod might run on a spot instance, another on an on-demand node.
- Node families vary. Different instance types mean different prices.
- Cluster-level billing. Costs show up at the node level, not the pod level.
So even if you know your total cluster cost, you still have no idea who’s actually responsible for it.
So what can we do?
Meet OpenCost: The Open Source Attempt at Solving This
OpenCost is a CNCF project that gives you visibility into Kubernetes costs at the workload level. It’s a step in the right direction:
- Tracks cost per namespace, deployment, pod, and service
- Works with most managed Kubernetes services
- Provides a Grafana dashboard for cost breakdown
If you’re tempted to try it, install it like this:
kubectl apply -f https://raw.githubusercontent.com/opencost/opencost/develop/deploy/opencost.yaml
Once installed, it exposes a /metrics
endpoint you can scrape with Prometheus—but if you don’t have Prometheus set up, OpenCost also includes an in-cluster UI that lets you explore cost data directly in your browser.
Great, so are we done here? Well, not exactly.
How to Use OpenCost to Attribute Costs to Pods
OpenCost exposes granular cost metrics through Prometheus. Here’s how to set it up and start attributing costs to workloads like pods, namespaces, and deployments.
Step 1: Deploy OpenCost to Your Cluster
Use the official manifest:
kubectl apply -f https://raw.githubusercontent.com/opencost/opencost/develop/deploy/opencost.yaml
This deploys the OpenCost service along with Prometheus scraping annotations enabled by default.
Step 2: Verify OpenCost Is Running
Check the pod status:
kubectl get pods -n opencost
You should see something like:
NAME READY STATUS RESTARTS AGE
opencost-XXXXXXX-XXXXX 1/1 Running 0 2m
Port forward the /metrics
endpoint to make it accessible:
kubectl port-forward -n opencost svc/opencost 9003
Then navigate to http://localhost:9003/metrics to see raw Prometheus metrics.
Step 3: Add OpenCost to Prometheus Targets
If you already use Prometheus, confirm that it’s scraping the OpenCost endpoint. Here’s an example of what to add to your prometheus.yml
:
- job_name: 'opencost'
static_configs:
- targets: ['opencost.opencost.svc.cluster.local:9003']
Reload Prometheus config and check /targets to verify the job is active.
Step 4: Query Cost Metrics by Pod
Once metrics are flowing, use Prometheus to attribute costs. For example:
sum(rate(opencost_container_cost[5m])) by (pod)
This gives you real-time pod-level cost over a 5-minute window.
Other useful queries:
Cost by namespace:
sum(opencost_container_cost) by (namespace)
CPU cost per pod:
sum(opencost_container_cpu_allocation_cost) by (pod)
Memory cost per deployment:
sum(opencost_container_memory_allocation_cost) by (deployment)
These metrics include container-specific cost based on node pricing, resource requests, and usage.
Step 5: Visualize in Grafana (Optional)
OpenCost provides a prebuilt Grafana dashboard:
- Import dashboard ID
16599
in Grafana. - Set the Prometheus data source.
- View real-time cost data by namespace, controller, pod, and label.
Step 6: Automate and Report
Once your data is accessible:
- Use
kubectl +
Prometheus API for ad-hoc analysis. - Integrate with tools like Thanos or Grafana Loki for longer-term retention.
- Automate daily or weekly reports using Prometheus Alertmanager or custom scripts.
So, what’s the catch with OpenCost?
As useful as OpenCost is, it falls short when things get complex:
- Naive cost allocation: It often assumes a flat rate per node or workload.
- No pod runtime consideration: If a pod runs for only 5 minutes on a node that lives for an hour, it still gets charged for the full hour.
- Cluster boundary blindness: You can’t view costs across multiple clusters in a single pane.
That’s not enough when you’re trying to make real cost-based decisions, especially in production environments or at scale.
So, again, what can we do?
Accurate Cost Attribution for Real Workloads
Zesty steps in where OpenCost stops. Built for real-world environments, it can handle dynamic workloads and offers uniquely precise cost visibility.
Here’s what makes Zesty different:
- Pod-level accuracy: Zesty tracks actual pod runtime, ensuring you only allocate costs for the time your pod was consuming resources, not idle time.
- Smarter discount attribution: It takes into account Savings Plans, Reserved Instances, and Spot pricing. So if one pod runs on an RI-backed node and another doesn’t—you’ll know.
- Multi-cluster view: Whether you’re running across dev, staging, and prod clusters—or across different regions—you get a unified cost view.
- No manual tagging required: Unlike other cost tools that require tagging everything to death, Zesty intelligently attributes cost to workloads without the manual overhead.
- Code-free cost intelligence: No need to change your YAML files or decorate your pods. Just install Zesty’s agent, and it starts tracking with minimal configuration.
Want to See It in Action?
Zesty makes it easy to get real-time, pod-level cost visibility—no tagging, no YAML changes, no guesswork. Just install the agent and start seeing exactly where your Kubernetes spend is going.
Pod Cost Calculation – Explained
In order to calculate the post of the pod we first need to breakdown the cost of the node it was running on:
We are using this formula:
resource_price = totalPricePerHour / ((cpu_count X cpu_ratio) + (ram_gib X ram_ratio)) X resource_ratio
Based off of GCP pricing, the CPU to RAM ratio is 88 to 12. Once we have the price per CPU per hour and the price per GB per hour, we can take that price and apply it to the pod according to its requests.
Example
a c5.large
instance has an hourly price of $0.085, 2
vCPU and 4
GB Memory. if we apply the above formula, we reach the following values: 1 vCPU per hour price: $0.03352
1 GB memory per hour price: $0.00449
Now, say we have a pod with the following requests:
We can now calculate its cost per hour:
CPU: (0.5/1) * 0.03352 = 0.01676
Mem: (256/1024) * 0.00449 = 0.0011225
Thus, the effective cost will be: $0.0178825
. Note that since the initial formula only cares about the totalPricePerHour, any discount (RI, SP, Spot) that the node has will be automatically taken into consideration.
A different scenario can exist in which the pod is using more of a given resource than its requests, for example:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 1
memory: 256Mi
For this pod spec, we might encounter a time frame in which the pod is using more than 500m. Another example is a pod that doesn’t have any requests for a given resource, e.g.:
requests:
memory: 256Mi
limits:
cpu: 500m
memory: 256Mi
This pod can use anywhere between 0 and 500m cpu cycles. In order to handle these scenarios and be able to accurately calculate a pod’s relative cost, for any given hour we will use the maximum value between its request and its average usage during this hour.
Pod/Node Effective Run Time
The last part of this is to also take into the effective run time of the pod and node during the hour. For example, a node that was running the whole hour and a pod that was only running part of the hour, the calculation should apply that ratio into the formula, so once we have the effective cost for the whole hour, we apply the following: pod_effective_cost = pod_runtime / node_runtime * pod_hourly_cost
. In the case both pod and node were running the whole 60 minutes, the effective cost remains the same as the hourly, but in case the pod was running part of the time, then this ratio is applied.
Pod Cost Breakdown Per Rate
Later, when we want to breakdown the pod cost per rate we take the ratio of the price and apply it backwards onto the node price breakdown.
Node total effective cost = (Node effective RI cost + Node effective SP cost + Node effective Spot cost + Node effective OnDemand cost)
Pod total effective cost = as calculated above
Pod OnDemand effective cost = (Pod total effective cost / Node total effective cost) * Node OnDemand effective cost
Pod Spot effective cost = (Pod total effective cost / Node total effective cost) * Node Spot effective cost
Pod RI effective cost = (Pod total effective cost / Node total effective cost) * Node RI effective cost
Pod SP effective cost = (Pod total effective cost / Node total effective cost) * Node SP effective cost