Cost Allocation Model

Understanding how CostPilot calculates costs helps you interpret the numbers you see and identify the highest-value optimisation opportunities. This page explains the allocation model without getting into implementation details.

The core problem

A Kubernetes node has a single hourly cost (e.g. an AWS m5.xlarge at $0.192/hour). But it runs many pods simultaneously. How do you attribute that $0.192 fairly between them?

CostPilot uses a weighted allocation model that considers both CPU and memory requests to divide the node’s cost between the pods running on it.

How allocation works

Step 1 — Determine node cost

CostPilot fetches current pricing for each node’s instance type from your cloud provider, using the node’s region and pricing type (on-demand, spot, or reserved). This gives an hourly cost per node.

For spot instances, the spot price at the time of ingestion is used. For reserved instances, CostPilot applies the equivalent effective hourly rate.

Step 2 — Split into CPU and memory fractions

Node costs are split into a CPU fraction and a memory fraction based on ratios typical for each cloud provider and instance family:

ProviderCPU fractionMemory fraction
AWS (general purpose)50%50%
GCP (general purpose)50%50%
Azure50%50%
Custom (self-hosted)ConfigurableConfigurable

These ratios can be overridden per-cluster in Settings → Clusters if you have specific knowledge of your pricing structure.

Step 3 — Allocate to pods by requests

Within each node, CPU cost is distributed proportionally to each pod’s CPU requests. Memory cost is distributed proportionally to each pod’s memory requests.

Example:

A node costs $1.00/hour. Split 50/50: $0.50 for CPU, $0.50 for memory.

PodCPU requestedMemory requested
Pod A500m512Mi
Pod B250m256Mi
Pod C250m256Mi
Total1000m1024Mi

CPU allocation:

  • Pod A: 500/1000 × $0.50 = $0.25
  • Pod B: 250/1000 × $0.50 = $0.125
  • Pod C: 250/1000 × $0.50 = $0.125

Memory allocation follows the same logic. Each pod’s total cost is the sum of its CPU + memory allocation.

Note

Allocation is based on requests, not actual usage. A pod that requests 1 CPU and uses 100m CPU still gets billed for 1 CPU’s worth of cost — this is intentional, as requests represent the capacity that was reserved for that pod.

Step 4 — Idle cost

After allocating to pods, the remaining node capacity (capacity with no pod requesting it) is accounted for as idle cost. CostPilot tracks idle cost separately and shows it as a distinct line in the Dashboard and Cost Explorer.

See Understanding Idle Costs for details.

Storage costs

For clusters with PersistentVolumes, CostPilot includes storage costs where pricing data is available. Storage costs are attributed directly to the pod or StatefulSet using the volume.

System pods

Kubernetes runs system pods in the kube-system namespace (CoreDNS, kube-proxy, etc.). CostPilot includes these in the namespace breakdown under kube-system. Their cost is typically small but non-zero.

Accumulation and aggregation

Raw metric records are stored at 1-minute granularity. When you view a 7-day or 30-day time range, CostPilot aggregates these records into hourly or daily summaries. Costs in aggregated views are the sum of the underlying per-minute allocations.

Custom pricing

For self-hosted clusters or clusters where CostPilot doesn’t have access to provider pricing, you can set a custom per-node hourly rate in Settings → Clusters. This rate is applied uniformly across all nodes in that cluster.