Kubernetes cost data only comes into being through allocation: on clusters billed by node, the cloud provider bills nodes, disks, load balancers and cluster fees, not pods (GKE Autopilot bills general-purpose pods by their requests), and only distributing that cost by requests and usage over time gives a container, a pod or a namespace a price. It matters for the bill because without that step a cluster remains one block of instance cost shared by several teams, and because the method chosen decides who pays for capacity that was reserved but not used.
How it works
From node to pod
A pod reserves capacity on a node through its requests. The Kubernetes scheduler only places it where the sum of requests stays below the node's capacity, even when actual utilisation is low, and a container may use more than it requested when the node has room. A pod's cost is therefore not its usage alone.
OpenCost, an incubating project of the Cloud Native Computing Foundation, publishes a vendor-neutral specification for this. In it, total cluster cost is asset cost (nodes, persistent volumes, disks, load balancers, network) plus overhead such as the provider's cluster management fees. Workload cost for CPU, memory and GPU is the greater of request and usage; storage follows the persistent volume claim's request. It is computed at container level and then summed by pod, deployment, namespace, label or cluster. Whatever part of the time-based asset cost no workload claims is idle cost. Idle, system workloads such as kube-system, and overhead are shared cost, which can be spread evenly, in proportion to consumption, or by a custom metric. For cost taken from the provider's bill, OpenCost connects to the provider's billing data.
AWS
Split cost allocation data adds cost per Amazon ECS task and per Kubernetes pod in Amazon EKS as line items of their own to the AWS Cost and Usage Report: two usage records per pod per hour for CPU and memory, three on instances with accelerators. split_line_item_split_usage is the greater of split_line_item_reserved_usage (configured) and split_line_item_actual_usage (used), split_line_item_split_cost the share of the EC2 instance's amortized cost, split_line_item_unused_cost the share of its unused capacity, and split_line_item_parent_resource_id the instance. It also adds the cost allocation tags aws:eks:cluster-name, aws:eks:namespace, aws:eks:node, aws:eks:workload-name, aws:eks:workload-type and aws:eks:deployment, activated by default, and imports up to 50 labels per pod (the first 50 in alphabetical order) as user-defined cost allocation tags, which the management account has to activate.
Azure
The AKS cost analysis add-on is built on OpenCost and reconciles the measured usage with invoice data. In Cost analysis it adds the Kubernetes clusters view with namespaces and assets, and shows four kinds of charge: idle charges (unused capacity), service charges (such as the Uptime SLA), system charges (capacity AKS reserves on each node) and unallocated charges. It requires the Standard or Premium tier and an Enterprise Agreement or Microsoft Customer Agreement; virtual nodes are not supported. Data is typically available after 8 to 24 hours.
Google Cloud
GKE cost allocation (Standard clusters) writes cluster and namespace as labels into the Cloud Billing detailed export: goog-k8s-cluster-name, k8s-namespace, k8s-workload-type, k8s-workload-name, and every pod label as k8s-label/ followed by its key. Allocation is based on requests, not usage. Capacity the system reserves on the node appears as the namespace kube:system-overhead, capacity nobody requested as kube:unallocated. Supported are vCPU, RAM, GPU, Persistent Disk and Cloud TPU SKUs; data takes up to three days to appear after enabling, and nothing is backfilled.
| Source | Where the data lands | Unit | Idle and shared cost | What is missing |
|---|---|---|---|---|
| OpenCost | its own installation in the cluster | container, aggregable | idle as a difference, spread by method | what the agent cannot see; bill data only through the integration |
| AWS | CUR 2.0, split line item columns | ECS task, EKS pod per hour | unused cost per pod in its own column | everything but the instance's CPU, memory and accelerators |
| Azure | Cost analysis views | namespace, asset | idle, system, service and unallocated charges | Free tier, other agreement types, virtual nodes |
| Google Cloud | detailed export in BigQuery | namespace, workload, label | kube:unallocated, kube:system-overhead | usage beyond the request, unsupported SKUs, the standard export |
What it means for your cost
Allocation does not change the bill, it distributes it; Google states explicitly that the total in the export stays the same. The rule differs: OpenCost charges the greater of request and usage, GKE the request alone, and AWS what the payer chose from three options when enabling split cost allocation data: resource requests alone, or the greater of request and usage, with usage metrics from either Amazon Managed Service for Prometheus or Amazon CloudWatch Container Insights. On accelerated computing instances (GPU, Trainium, Inferentia) AWS always allocates by requests, whichever option was chosen. A team that sets high requests therefore carries capacity it reserves and does not use, and the same usage yields different team totals depending on the source.
For the report, what matters is how idle, system and unallocated cost are handled. As separate rows they show how much of the cluster belongs to nobody; the share of cluster cost that lands on namespaces is the allocation coverage. Spread across teams, the team totals match the bill and the unused capacity drops out of sight. Whether it can be removed is a question of idle and orphaned resources; what a node costs is covered in virtual machines and instance families.
Namespaces and labels are the cost allocation keys inside a cluster, as tags are outside it (tags and labels). On AWS the split data distributes only the instance, on GKE only the supported instance, disk and TPU SKUs; load balancers, cluster fees and data transfer stay outside the pods there. Where the raw data sits is covered in Google Cloud billing export and Azure cost exports.
Where it goes wrong
- Pod cost is computed from usage alone. Symptom: the namespaces add up to far less than the node cost. Cause: requests reserve capacity regardless of usage; the remainder is idle and has to appear as its own row or be spread.
- Namespace labels are missing from the GKE export. Symptom: node cost only, no
k8s-namespace. Cause: cost allocation is not enabled, is less than three days old, or the standard export is being queried. - Pod labels are missing despite cost allocation. Symptom: the namespace is there, no
k8s-label/labels. Cause: if a pod has more than 50 Kubernetes labels, GKE carries none of them over. - The AKS view stays empty. Symptom: no namespaces in Cost analysis. Cause: the cluster runs on the Free tier, the subscription is not under an EA or MCA, or the workloads run on virtual nodes.
- Team totals do not add up to the cluster cost. Symptom: a gap between namespaces and the bill. Cause: idle, system overhead, unallocated capacity and cluster-wide cost sit in rows of their own or outside the pod data.
Sources
Read on 2026-10-16. OpenCost Overview and OpenCost Specification; Kubernetes Resource Management for Pods and Containers; AWS Understanding split cost allocation data, Enabling split cost allocation data, Using split cost allocation data with Amazon CloudWatch Container Insights, Using Kubernetes labels for cost allocation in EKS and Split line item columns; Microsoft Azure Kubernetes Service (AKS) cost analysis; Google Get key spending insights for your GKE resource allocation and cluster costs and GKE pricing.