Kubernetes Cost Optimization Starts Below the Pod

Categories:
Business
Date:

October 23, 2026

Time:
5 min

Buy a 4 GiB node on GKE or AKS, declare 110 pod slots on it, and only about 72.5% of its memory is schedulable. The rest is reserved before a single pod lands, and rightsizing never gets it back. That is why Kubernetes cost optimization that stops at pod requests often changes less than expected: requests drive scheduling, while invoices are written in node-hours — and several layers sit between the two. This piece covers those layers, the arithmetic that shows which one holds your money, and the discounts that apply whichever it is.

Rightsizing changes a request, not an invoice

A resource request is an input to placement, not to billing. Cluster Autoscaler adds a node when pods cannot be scheduled, and decides whether a node can be removed because “CA simulates kube-scheduler behavior” against the remaining nodes (Kubernetes Autoscaler FAQ). Requests drive both decisions. Neither is a price.

On a node-billed cluster, the billing event is a node appearing, disappearing or changing size. A rightsizing pass that cuts requests by 30% changes the bill only when that changes the node count or, with autoscalers that pick instance types from pending requests, the node size.

Cluster Autoscaler’s removal rule is narrower than most teams assume. “A node is considered for removal when all below conditions hold”: the summed CPU and memory requests of its pods are “smaller than 50% of the node’s allocatable” (DaemonSet and mirror pods “are included by default”, configurable by flag); every pod on it can be moved to another node; and the node has no scale-down-disabled annotation. A node unneeded “for more than 10 minutes” is terminated. The 50% is configurable with --scale-down-utilization-threshold.

For Cluster Autoscaler, read the threshold as a cliff, not a gradient: cutting a node’s requests from 95% to 55% of allocatable frees nothing; from 55% to 45% can free a whole node. Karpenter works differently. Its consolidation has no utilization threshold — under the WhenEmptyOrUnderutilized policy it considers “any node that can be removed or replaced to reduce cost,” deleting a node when “all of its pods can run on free capacity of other nodes” or replacing it with a cheaper one. Which autoscaler you run changes where rightsizing pays.

The slice every node reserves before a pod lands

The number the scheduler can fill is allocatable, not capacity. GKE: “GKE reserves a predefined quantity of resources for system functionality and node reliability. The remaining resources that are available for your workloads are called allocatable resources” (Google Cloud documentation, updated 13 October 2026).

Both platforms publish the formula, and both are regressive — the reserved share falls as the node grows. On GKE node pools created on 1.37 or later, “MemoryReserved = Min(EarlierMemoryReservation, (15 MiB * MaxPodsPerNode) + BaseOverhead)”, with a 500 MiB base overhead on Container-Optimized OS, and “An additional 100 MiB of memory is reserved for Pod eviction thresholds.” AKS reserves “the lesser value of: 20 MB * Max Pods supported on the Node + 50 MB or 25% of the total system memory resources,” plus a memory.available < 100 Mi eviction rule (Microsoft Learn, updated 20 October 2026).

Applied at 110 max pods (Container-Optimized OS on GKE). GKE states reservations in MiB/GiB and AKS in MB/GB, so each column is computed in its vendor’s units; compare the percentages.

Node memoryGKE allocatableGKE shareAKS allocatableAKS share
42.90 GiB72.6%2.90 GB72.5%
86.10 GiB76.3%5.90 GB73.8%
1613.80 GiB86.3%13.65 GB85.3%
3229.80 GiB93.1%29.65 GB92.7%
6461.80 GiB96.6%61.65 GB96.3%
128125.80 GiB98.3%125.65 GB98.2%

Memory only. The GKE column adds the 100 MiB eviction threshold on top of the Min(...) result, as the page presents it; the AKS column follows the page’s own worked examples, which subtract 0.1 GB. 110 max pods is an assumption, not a documented default.

The consequence has nothing to do with your workloads. Buy 16 GiB as four 4 GiB GKE nodes and 11.61 GiB is schedulable; buy it as one 16 GiB node and 13.80 GiB is — 2.19 GiB less for the same memory, lost to node shape alone. On small nodes both vendors cap kube-reserved at about a quarter of memory, which is why the 4-unit row lands at 72.6% and 72.5% from two different formulas.

CPU matters far less: GKE caps CPU reservation at “1 vCPU (1000 mCPU) or less for standard, non-fractional compute instances,” which comes to 80 mCPU on a 4 vCPU node; AKS publishes a table from 60 millicores at 1 core to 740 at 64.

Pod density is paid for in memory

Both formulas contain a term rarely treated as a cost lever: max pods per node. GKE reserves 15 MiB per pod slot, AKS 20 MB — for slots you declare, not pods you run. On a 16 GB AKS node:

Max pods per nodekube-reservedAllocatable
30650 MB15.25 GB
501,050 MB14.85 GB
1102,250 MB13.65 GB
2504,000 MB (25% cap applies)11.90 GB

Raising max pods from 30 to 110 to improve bin-packing costs 1,600 MB per node — 10% of a 16 GB node. On GKE the same change costs 1,200 MiB, 7.3% of a 16 GiB node. Packing more pods per node is often the right call, but it is a memory purchase at a published rate, and it never shows up as a line item — it shows up as a node you would not otherwise have needed.

Requests-billed or node-billed: the variable that reorders everything

One variable reorders every item on a Kubernetes cost list: whether the platform charges for pod requests or for node-hours. Everything above applies to node-billed clusters. On a requests-billed platform there is no allocatable slice to lose and no bin-packing remainder; rightsizing is most of the game.

Google publishes both prices. GKE Autopilot charges “for the CPU, memory, and ephemeral storage resources that your running Pods request” — general-purpose Autopilot pods at $0.0445 per vCPU-hour and $0.0049225 per GiB-hour in Iowa (us-central1), on demand. A general-purpose n4-standard-4 node — 4 vCPU, 16 GiB — is $0.1814 per hour on demand (Google Cloud pricing pages, read 22 October 2026).

That node’s allocatable envelope is 3.92 vCPU and 13.80 GiB. Bought as Autopilot requests it costs $0.2424 per hour — 33.6% more than the node. So, at list prices, pod-billing is cheaper whenever your requests would fill less than about 75% of the node:

Share of node allocatable filled by requestsAutopilot costNode costCheaper
30%$0.0727/h$0.1814/hAutopilot (0.40×)
50%$0.1212/h$0.1814/hAutopilot (0.67×)
60%$0.1454/h$0.1814/hAutopilot (0.80×)
74.8%$0.1814/h$0.1814/hBreak-even
90%$0.2181/h$0.1814/hNode (0.83×)
100%$0.2424/h$0.1814/hNode (0.75×)

us-central1 on-demand list prices. Autopilot runs on its own container-optimized platform, not on n4 machines, so this compares the same requests priced two ways rather than identical products. Recompute for your region, machine family and discounts.

Two qualifiers move the break-even against Autopilot. First, Autopilot “increases values that don’t meet the required minimums or CPU-to-memory ratios,” so small or unusually shaped pods are billed for more than they request. Second, the $0.10 per cluster per hour fee applies “irrespective of the mode of operation,” so it cancels out here — but GKE’s free tier gives $74.40 a month per billing account, enough for one zonal Standard or Autopilot cluster.

Put the break-even next to Cluster Autoscaler’s default criterion and a band appears that neither vendor prints: below 50% fill the autoscaler can consolidate; above about 75% node-billing wins outright; between the two, a Cluster Autoscaler cluster will not remove the node and pod-billing would have been cheaper at list price. That 60%-ish fill is exactly what many teams choose for failover headroom. With Karpenter or a more aggressive autoscaling profile, the band narrows.

AWS has the same shape with less published detail. EKS Auto Mode keeps node-billing and adds a management fee per instance: the pricing page states no percentage, but in its Example 4 every instance’s fee — $0.03672 against a $0.306 c6a.2xlarge, $0.17208 against a $1.434 total — works out to exactly 12%.

Discounts apply on top of all of this

Spot capacity and committed-use discounts are usually the largest single levers on a Kubernetes bill, and they apply to both billing models: GKE lists Spot and committed-use rates for Autopilot pods as well as for nodes. They change the absolute numbers above, not the logic — run the break-even with the rates you actually pay, and keep interruption-tolerant workloads on Spot only where eviction is acceptable.

The line items with no pod attached

Per-pod cost tools cannot see these, which is why they survive rightsizing.

  • The cluster fee. $0.10 per cluster per hour on both GKE and EKS — $73 a month, $876 a year, $8,760 a year for ten clusters, before a node boots (GKE’s free tier offsets one zonal or Autopilot cluster per billing account). Namespaces are free.

  • Version drift. EKS extended support is $0.60 per cluster per hour against $0.10 standard; GKE’s Extended channel past standard support is also $0.60. That is $365 a month per cluster for an upgrade you did not do.

  • Cross-zone chatter. On AWS, a topology-unaware service mesh generates cross-zone traffic in proportion to pod count rather than business value, and transfer between Availability Zones in the same region is charged at $0.01 per GB in each direction — every cross-zone gigabyte is billed twice.

  • Egress through a NAT gateway. The AWS VPC pricing example for US East (Ohio) charges $0.045 per hour and $0.045 per GB processed — roughly $32.85 plus $45 for a 1 TB month. Private node pools pay processing on image pulls at every scale-out; see the cloud egress fees comparison.

  • The tier chosen at creation. AKS Free gives “best-effort uptime (no financially backed SLA)”; Standard carries “99.95% availability of the Kubernetes API server” with availability zones. A reliability purchase, sometimes made by accident.

What to measure first

  1. Run kubectl describe node for one node of every shape you own and record allocatable against capacity. That ratio is your floor.

  2. Per node, sum pod requests and divide by allocatable. Keep the distribution, not the average.

  3. Count the nodes in the 50–75% band (with Cluster Autoscaler defaults). That count times the hourly node rate is what the requests-versus-nodes decision is worth to you.

  4. Record max pods per pool and multiply the gap between declared and actual peak pod count by 15 MiB (GKE) or 20 MB (AKS).

  5. Split the bill into node-hours, cluster fees, data transfer and storage. Rightsizing addresses only the first.

  6. Re-run the break-even with your own region, machine family, Spot and committed-use rates, for your three largest pools.

  7. Change one pool, wait a billing cycle, compare node-hours rather than requests. If node-hours did not move, the saving was not real yet.

What breaks in production

  • A pod with no controller pins its node. Cluster Autoscaler will not remove a node running “Pods that are not backed by a controller object.” One debugging pod started with kubectl run can hold a node for months.

  • Local storage does the same. Pods with local storage — hostPath or non-memory emptyDir volumes — block removal unless annotated, which makes scratch space a cost decision.

  • A restrictive PodDisruptionBudget stops consolidation. Karpenter is direct about it: “Pods with blocking PDBs will not be evicted by the Termination Controller or be considered for voluntary disruption actions.” A single-replica deployment with minAvailable: 1 is an undrainable node.

  • kube-system pods without a PDB, and safe-to-evict: "false" left over from an incident, block scale-down too. Grep for both.

  • Trimming limits is a runtime change, not an accounting one. Google’s guidance: “For CPU, configure requests to meet your service-level objectives (SLOs) but leave limits unrestricted,” while “For memory, ensure that the requested allocation matches the memory limit.” A tool that trims CPU limits alongside requests works against that advice.

  • Autoscalers can fight. A horizontal autoscaler adding replicas against a vertical one shrinking requests can settle somewhere dearer than either alone.

Which layer is yours

Are you billed for requests or for nodes? If requests, rightsizing and discounts are the programme. If nodes, continue.

What is your fill distribution? Mostly above 75%: node shapes are right and the money is in discounts and the no-pod line items. Mostly below 50%: the autoscaler should already be consolidating, so find what blocks it before touching a request. Clustered in 50–75%: you are paying node prices for request-shaped usage — consider a more aggressive autoscaler or a billing-model change.

Is your node shape wrong? If small nodes dominate, a quarter of their memory goes to kube-reserved. Larger nodes recover allocatable share — and enlarge the blast radius of one node failure.

Kubernetes on infrastructure you choose

If the arithmetic says the platform itself is the line item, the alternative is node-billed Kubernetes on dedicated or bare-metal servers, where there is no per-cluster fee and no managed-platform margin on top of the hardware. INXY.hosting’s DevOps and managed infrastructure team builds and runs Kubernetes clusters on the infrastructure that fits the workload.

Send us the output of steps 1 to 4 and we will show which layer your money is in. For bare-metal economics see the dedicated server pricing guide; if the platform is the problem, cloud repatriation is the next read.

FAQ

Does rightsizing reduce Kubernetes costs?

On a requests-billed platform such as GKE Autopilot, directly. On a node-billed cluster, only when it lets the autoscaler remove or shrink a node. With Cluster Autoscaler that means a node’s requests falling below the scale-down threshold — 50% of allocatable unless configured otherwise — and nothing on the node blocking eviction.

What is node allocatable in Kubernetes?

Allocatable is the portion of a node’s capacity the scheduler may fill. Managed platforms subtract a reservation for the kubelet and system daemons plus an eviction threshold. The share is regressive: about 27% of a 4 GiB node and under 2% of a 128 GiB node at 110 max pods, by GKE’s formula.

Is GKE Autopilot cheaper than a Standard cluster?

It depends on fill. At us-central1 on-demand list prices, buying a 4 vCPU / 16 GiB node’s full allocatable as Autopilot requests costs 33.6% more than the node, so Autopilot is cheaper when requests would fill less than about 75% of each node. Autopilot’s minimum requests and CPU-to-memory ratios push that break-even lower.

Why does max pods per node affect cost?

Both platforms reserve memory per pod slot, not per running pod: 15 MiB on GKE 1.37 and later, 20 MB on AKS. Declaring 110 slots instead of 30 on a 16 GB AKS node removes 1,600 MB — 10% of it — whether those pods exist or not.

What Kubernetes costs do per-pod cost tools miss?

Anything without a pod attached: the per-cluster management fee, extended-support premiums for clusters left on old versions, cross-zone traffic between chatty services, NAT gateway hourly and per-GB processing, idle volumes and load balancers, and the reliability tier chosen at cluster creation.

INXY Hosting solutions

Ready to strengthen your digital defenses? Schedule a demo call with our experts today to discover how INXY can help protect your business against cyber threats and ensure uninterrupted operations.

Book a Demo

Read more articles