Kubernetes Cost Basics
This page is a hands-on tour of where Kubernetes spend actually lands, with the commands and manifests to see each line item for yourself.
Search across all documentation pages
This page is a hands-on tour of where Kubernetes spend actually lands, with the commands and manifests to see each line item for yourself.
kubectl top works.Quick check that metrics are flowing:
kubectl top nodes
kubectl top pods -AIf those return numbers, you can compare real usage against reservations.
The allocatable figure, not the raw hardware, is what the scheduler can hand out.
kubectl describe node <node-name> | grep -A6 "Allocatable"Requests reserve capacity; limits cap it.
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].resources}'This gap is idle headroom, and it is pure waste.
kubectl describe node <node-name> | grep -A8 "Allocated resources"kubectl top node to see actual burn.Each LoadBalancer service is a billed cloud load balancer.
kubectl get svc -A --field-selector spec.type=LoadBalancerDisks bill by provisioned size, not by bytes used.
kubectl get pvc -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,SIZE:.spec.resources.requests.storageRetain policy keep billing after the pod is gone.The core basic recipe: set requests near observed usage.
resources:
requests:
cpu: "150m"
memory: "256Mi"
limits:
memory: "256Mi"kubectl top, not a guess.Labels are what any cost tool groups spend by.
metadata:
labels:
team: payments
app: checkout
environment: prodnamespace, team, and environment are the highest-value dimensions.Quotas stop one team from silently reserving the whole cluster.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: payments
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
services.loadbalancers: "2"services.loadbalancers prevents surprise load balancer sprawl.LimitRange so pods without explicit requests still get sane defaults.Cross-zone egress is metered per gigabyte and easy to miss.
kubectl get pods -A -o wide | awk '{print $8}' | sort | uniq -cA node running 24x7 sets a baseline you pay regardless of load.
kubectl get nodes -o custom-columns=NAME:.metadata.name,TYPE:.metadata.labels.node\.kubernetes\.io/instance-typeStack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).
Reviewed by Chris St. John·Last updated Jul 19, 2026