Compute cost per Kubernetes app
Costs → Compute (/costs?tab=compute) shows what each app running on Kubernetes costs in CPU and memory, from what its pods reserved and what they used. It also shows each cluster’s idle capacity and the workloads that are sized wrong.
Turn it on
Section titled “Turn it on”Compute cost needs two kinds of reading from the Shield360 operator:
| Value | Sends |
|---|---|
systemLogs.node.kubeletStats: true | What each pod uses, from each node’s kubelet, once a minute |
systemLogs.clusterEvents.resourceRequests: true | What each pod requests and limits, and what each node can hold, from the Kubernetes API, once a minute |
helm upgrade shield360-operator oci://ghcr.io/thinkfleetai/charts/shield360-operator \ --version 0.4.0 -n shield360-system --reuse-values \ --set systemLogs.node.kubeletStats=true \ --set systemLogs.clusterEvents.resourceRequests=trueresourceRequests needs chart 0.4.0 or later. With only kubeletStats, pods are charged for what they use, and there is no idle line or right-sizing comparison.
How cost is worked out
Section titled “How cost is worked out”Each hour, each pod is charged for the larger of what it requested and what it used, CPU and memory separately:
- CPU at the cluster’s rate per core-hour
- Memory at the cluster’s rate per GiB-hour
A pod that reserves 2 cores but uses 0.3 is charged for 2, because no other pod can use them. Node capacity that no pod reserved or used is the cluster’s Idle line. It is never spread over the apps without being shown.
Where the rate comes from
Section titled “Where the rate comes from”| Priced from | When | What it means |
|---|---|---|
| Your rate | You set one with Set rate on the cluster’s row | Your own price per core-hour and per GiB-hour, for example a negotiated or blended rate. It wins over the bill and list price |
| Bill | The bill project you named with Set rate, else a project on Costs → Cloud with the cluster’s name (any case), or the AKS node resource group MC_<group>_<cluster>_<region> | The bill’s compute (EC2 instances, Azure Virtual Machines or Compute Engine) for that project over the last seven complete days, laid over the cluster’s capacity. Discounts and Savings Plans are included |
| List price | No bill project matches | Public on-demand averages: $0.031611 per core-hour and $0.004237 per GiB-hour |
To price a cluster from its bill, tag its nodes with the cluster’s name and connect the cloud bill grouped by that tag. EBS volumes, NAT gateways and data transfer are not node capacity, so they are not in the rate.
Which app a pod belongs to
Section titled “Which app a pod belongs to”- The service whose traces name the pod, from
k8s.pod.name, orhost.name, which in Kubernetes is the pod’s name - The pod’s workload (Deployment, StatefulSet, DaemonSet, Job or CronJob)
- A workload name taken from the pod’s generated name
Hover an app’s name to see which one applied.
Setting a rate or a bill project needs the costs.manage permission on the project, and every change is recorded in the audit log.
Managed services and servers
Section titled “Managed services and servers”The rest of the cloud bill is added where its project is named after something on the page:
| The bill project is named after | Its cost goes to |
|---|---|
| An app, or a namespace only one app runs in | That app’s Services (databases, storage, queues) or, for machines, its Servers |
| A cluster | The cluster’s Cluster services (control plane, volumes, load balancers), shared by its apps and not split between them |
| Nothing on the page | Not matched to an app or cluster, listed with its largest services but left out of the totals |
AI services such as Bedrock and Azure OpenAI are left out here, because Total AI cost already counts them.
Hosts that the Shield360 host collector reports with --host-metrics, and that are not Kubernetes nodes, are listed under Servers. Each host is priced for its cores and memory at the servers rate, list price unless you set one, and charged evenly to the services its traces report. A host whose app already has billed machines is shown but not charged twice.
Cost by route and per customer
Section titled “Cost by route and per customer”Each app’s cost, pods plus services plus servers, is split across its requests by server time. A request is a server span, or a trace’s root span, so a background job that starts its own trace counts too.
- Cost by route groups requests by method and route template, such as
POST /export, else by span name. It shows each route’s share of the app, its cost, its monthly pace and its cost per 1,000 requests. - Cost to serve each customer adds up a customer’s requests across every app. Requests are tagged the same way as for AI cost per customer:
shield360.customer.tenant_idon the span or its resource. Requests with no customer are a row of their own, so the customers and that row add up to the apps.
This is an estimate. Time spent waiting on a slow call counts the same as time spent working, and work done outside traced requests is spread over the requests that were traced. An app with a cost but no request in its traces is listed as not split. These figures are shown on this page only; the AI cost and margin on Costs → Customers do not include them.
What makes pods big
Section titled “What makes pods big”The What makes pods big table lists workloads with one or more findings:
| Finding | Meaning |
|---|---|
| Over-requested | Requests are at least 1.5 times what the workload needs, and smaller requests would save at least $1 a month |
| Uses more than it reserves | Its p95 CPU or peak memory is above its request. It can be throttled, evicted or killed when the node is busy |
| Memory spikes | Peak memory is at least three times the typical (median). Something periodic, such as a job, an import or one route, sets the size every pod pays for |
The suggested requests are p95 CPU plus 20% and peak memory plus 15%. Memory is sized for the peak, not the p95, because a pod that runs out of memory is killed.
What runs at the peak
Section titled “What runs at the peak”For a workload with Memory spikes, select What runs at the peak. Shield360 takes each of its pods’ three highest-memory minutes in the period, at most 20 pods, and lists the requests that were running then: started before the peak and still running within a minute of it. Each request’s share at the peak is compared with its share of the same pods’ requests over the whole period:
| Column | Meaning |
|---|---|
| At the peak | Requests of this kind in flight across the peak minutes |
| Share at peak / Share usually | Its share of the requests at the peaks, and over the period |
| More common | How many times more common it is at the peak, or Only at the peak |
Requests at least twice as common at the peak are listed first. When none is, the most common ones are shown. The pods have to send traces for anything to be named.
Moving that work to its own job or a queue, or streaming it instead of loading it whole, is often cheaper than making every pod big enough for it.
Limits
Section titled “Limits”- The page reads at most the last seven days of the selected period and projects monthly figures from that pace.
- Every figure is an estimate of a share, not an invoice.
- A billed rate covers the bill’s last seven complete days, so a cluster that changed size recently can read high or low until the bill catches up.
- At most 2,000 pods, 500 nodes and 500 hosts are read; the page says when more reported.
- Bill amounts are the average per hour over the last seven complete days of bill, times the hours in the window.