AI Cost Visibility & Optimization Understand, allocate & reduce your AI costs - Learn More

GKE Cost Optimization: Cut Kubernetes Spend on GCP

Google Kubernetes Engine bills differently than compute. You pay for nodes whether pods use them or not in Standard mode, or you pay for pod resource requests in Autopilot — either way, most teams overspend by 30-50% on unused capacity, over-set requests, and poor bin-packing. This guide walks through where GKE spend actually leaks, how to right-size pods and nodes based on real utilization data, and how to coordinate autoscalers without creating cost blowouts or performance degradation.

How GKE Pricing Actually Works

GKE charges in three layers: cluster management, compute resources, and egress. The billing model determines whether optimization starts at the pod level (Autopilot) or node level (Standard), which is where most confusion starts.

Cluster management fee

GKE charges $0.10 per hour per cluster (~$73/month) across Standard and Autopilot clusters, regardless of cluster size. The fee covers cluster management, not worker-node compute.

For organizations running 10+ clusters (dev, staging, prod across multiple teams or regions), the management fee alone costs $730/month before compute. Cluster consolidation — running multiple workloads in fewer clusters with namespace isolation — can save $5,000-10,000/year in management fees at that scale.

Standard mode: you pay for nodes, whether pods use them or not

In Standard mode, you provision node pools with specific machine types (e2-standard-4, n2-highmem-8, etc.) and pay for every running node hour at the machine type's hourly rate. An n2-standard-4 node (4 vCPU, 16 GiB) costs ~$0.194/hour in us-central1 — $141.62/month per node.

Kubernetes schedules pods onto nodes based on resource requests (not actual usage). If your 10 pods each request 0.5 vCPU but only use 0.15 vCPU on average, you're paying for 5 vCPUs of capacity but consuming 1.5 vCPUs. The delta is idle waste — you bought the node, the capacity sits unused, and you pay full price.

Autopilot mode: you pay for pod resource requests

Autopilot charges $0.0445 per vCPU-hour and $0.0049 per GiB-hour for the resources you declare in pod specs. A pod requesting 1 vCPU and 2 GiB costs ~$40/month. Google manages the nodes, scales capacity automatically, and bills based on pod-level requests, not node-level provisioning.

Autopilot workloads that request specific hardware, machine series, or accelerators can instead use node-based billing, so verify the billing model for the ComputeClass you use.

If your pods over-request resources (common with legacy deployments copying VM-era sizing), you pay for the inflation directly. A 20-replica service with each pod requesting 1 vCPU but using 0.3 vCPU wastes about $455/month in excess CPU-request charges in Autopilot. The cost equation is simpler than Standard mode (no node tetris), but request discipline matters more because every inflated request shows up on the bill.

The free tier and what it covers

GKE includes a $74.40/month free tier — enough to cover the cluster management fee for one Autopilot or zonal Standard cluster. The credit does not apply to regional Standard cluster fees. The free tier does NOT cover compute resources (nodes in Standard, pod requests in Autopilot) — only the cluster management fee.

Beyond one cluster or higher workload density, the free tier is negligible — a 50-node production cluster paying $7,000/month in compute barely notices the $73 management fee.

Autopilot vs Standard: Which Is Actually Cheaper?

The cost winner depends on team ops capacity and workload predictability. Multiple 2026 analyses conclude: "if you will not actively bin pack, Autopilot is cheaper; if you will, Standard wins".

Worked comparison: 30-pod workload

Metric

Autopilot (2026 pricing)

Standard (n2-standard-4, 5 nodes)

Pod config

30 pods × 0.5 vCPU, 1 GiB each

Same (15 vCPU total, 30 GiB total)

CPU cost

30 × 0.5 × $0.0445/hr × 730 hrs = $487.28

5 nodes × $0.194/hr × 730 hrs = $708.10

Memory cost

30 × 1 GiB × $0.0049/hr × 730 hrs = $107.31

Included in node pricing

Cluster fee

$73.00

$73.00

Monthly total

$667.59

$781.10

Packing

Pay per request

15 vCPU requested across 20 raw node vCPUs; actual allocatable capacity is lower after system reservations

In this example, Autopilot is about $114/month (15%) cheaper. Standard can still win when workloads pack densely enough, use lower-cost node types, or receive applicable node-level discounts.

Where Autopilot wins (small teams, spiky workloads, low ops capacity)

Autopilot is cheaper when:1. No dedicated Kubernetes expertise — teams moving from PaaS (Heroku, App Engine) or without platform engineers to manage node pools, OS patching, and bin-packing optimization2. Highly variable pod counts — workloads that swing 3x+ daily (e-commerce during sales, ML training pipelines) where Standard mode would leave nodes idle between bursts3. Small clusters (<10 nodes, <$500/month compute) — avoiding manual node sizing and poor bin-packing can make Autopilot cheaper when the operational overhead of Standard outweighs potential node-level savings

Where Standard wins (dense bin-packing, Spot-heavy, GPU workloads, custom nodes)

Standard mode is cheaper when:1. Predictable workloads — pod counts stable within ±20% month-over-month; teams can right-size node pools and directly control the underlying machine mix. Standard also supports resource-based Compute Engine CUDs, while both Standard and Autopilot can benefit from eligible Compute Flexible CUDs2. Spot-heavy workloads — Standard supports direct control over Spot node-pool architecture and capacity mix. Autopilot also supports Spot Pods for fault-tolerant workloads via the cloud.google.com/gke-spot: "true" node selector3. GPU workloads — Standard mode supports GPU-specific node pools (for example, n1-standard-4 + 1× T4 GPU) and custom machine types; Autopilot GPU support is limited to specific machine families and cannot mix GPU/CPU workloads on the same nodes efficiently4. Large scale (100+ nodes) — at $10,000+/month compute, the $73 management fee becomes <1% of cost, and applicable committed use discounts can further reduce eligible node costs

For production workloads with dedicated FinOps oversight, Standard mode typically runs 20-35% cheaper than Autopilot at 75%+ sustained utilization.

The migration consideration

Switching from Standard to Autopilot (or vice versa) requires cluster recreation — GKE does not support in-place mode changes. Migration checklist:

  • Backup all PersistentVolumes and application state (Velero, native GCP backups)
  • Review node selectors, affinity/anti-affinity, taints/tolerations, and other node-level assumptions — some behaviors are managed or restricted differently in Autopilot
  • Test Autopilot workload limits and restrictions — check CPU, memory, storage, accelerator, privileged-workload, and volume constraints for the specific ComputeClass you plan to use
  • Plan DNS cutover — stand up new cluster, validate, shift traffic via LoadBalancer IP swap or Ingress migration

For clusters >50 nodes, budget 2-4 weeks for migration, testing, and rollback planning. The cost delta must justify the ops investment — migrating to save $200/month on a $5,000/month cluster is rarely worth the engineering hours.

Where GKE Spend Actually Leaks

Most GKE cost waste happens in four areas: over-set pod requests, poor bin-packing, idle infrastructure, and orphaned resources. These leaks compound — over-requesting pods prevents efficient bin-packing, which requires more nodes, which leaves more idle capacity.

Over-set pod resource requests (the single biggest driver of GKE waste)

Pod resource requests determine Kubernetes scheduling, but teams often copy-paste requests from legacy deployments or set them to "safe" highs without measuring actual usage. A Node.js API pod requesting 1 vCPU and 2 GiB but averaging 0.15 vCPU and 800 MiB wastes 85% of its declared resources.

Impact: In Autopilot, over-requests inflate the bill directly (paying for 1 vCPU when 0.2 vCPU would suffice). In Standard mode, over-requests reduce bin-packing density — a node that could fit 20 right-sized pods instead fits only 8 over-requested pods, forcing the cluster to provision 2.5x more nodes.

Example: A 50-pod microservices cluster with each pod requesting 1 vCPU but using 0.3 vCPU:

  • Current state: 50 vCPU requested = 14 n2-standard-4 nodes = $1,982.68/month node cost + $73 cluster fee = $2,055.68/month
  • Right-sized (0.4 vCPU requests): 20 vCPU requested = 6 n2-standard-4 nodes = $849.72/month + $73 = $922.72/month
  • Savings: $1,132.96/month (55% reduction) from one configuration change

To fix: deploy Vertical Pod Autoscaler in recommendation mode (updateMode: "Off"), collect 7-14 days of metrics, review recommendations with kubectl describe vpa, then apply updated requests during a maintenance window.

Poor bin-packing and node fragmentation

Kubernetes scheduler places pods on nodes with sufficient allocatable resources (total node capacity minus system overhead: kubelet, kube-proxy, OS reserves). A 4 vCPU node typically has ~3.8 vCPU allocatable. If pods request awkward sizes (0.9 vCPU, 1.3 vCPU), nodes fragment — leftover capacity is too small for new pods, forcing cluster scale-up even when aggregate capacity exists.

Bin-packing anti-patterns:1. Uneven pod sizes — mixing 0.1 vCPU pods with 3.5 vCPU pods on the same node pool creates fragmentation (leftover 0.3 vCPU capacity is unusable)2. Overly strict topology spread or anti-affinity — forcing replicas across nodes or zones can leave otherwise usable node capacity stranded3. DaemonSets eating allocatable capacity — monitoring agents, log shippers, security tools reserve 0.2-0.5 vCPU per node; teams forget to account for this when calculating node capacity

Fix: Separate workloads into dedicated node pools by resource profile (small pods on e2-standard-4, large pods on n2-standard-16), use topology spread constraints to balance pods across zones, and measure *effective allocatable capacity* (node capacity minus DaemonSet overhead) when sizing pools.

Idle node pools and over-provisioned system pools

Cluster Autoscaler provisions new nodes when pods are unschedulable due to resource constraints, but it waits 10 minutes (default) after a node becomes underutilized before removing it. For bursty workloads (nightly batch jobs, CI/CD pipelines), this delay keeps nodes running for 10 minutes after the workload completes — $0.03-0.05/night per node in wasted capacity.

Compounding with PodDisruptionBudgets: If a PDB prevents pod eviction (for example, minAvailable: 3 for a 3-replica deployment spread across 3 nodes), Cluster Autoscaler cannot remove any node without violating the PDB. This is a common cause of "stuck" nodes that should scale down but don't, costing $50-100/month per stuck node.

Over-provisioned system pools: Many teams create a dedicated "system" node pool for kube-system pods (CoreDNS, kube-proxy, metrics-server) sized at 2-3 nodes with minReplicas: 2 to ensure HA. For small clusters, this system pool represents 30-40% of total nodes but hosts <5% of workload. Right-size system pools to 1-2 e2-small nodes unless the cluster exceeds 50 nodes.

Orphaned persistent volumes and load balancers

GKE automatically provisions PersistentVolumes (regional or zonal disks) and GCP Load Balancers when you create PVCs and LoadBalancer-type Services. Deleting a Deployment does not automatically delete its PVCs. When a PVC/PV is deleted, the PV's reclaim policy determines whether the underlying storage is deleted or retained.

Cost impact: In us-central1, orphaned persistent disks cost about $0.04/GiB-month (standard PD) or $0.17/GiB-month (SSD PD). A cluster with 50× 100 GiB orphaned disks wastes about $200/month on standard PD or $850/month on SSD PD. Orphaned load balancers can also continue generating forwarding-rule and related charges.

List PVs in Released state (orphaned)

kubectl get pv --all-namespaces | grep Released

Find GCP disks not attached to any VM

gcloud compute disks list --filter="-users:*" --format="table(name,sizeGb,zone)"

Prevention: Set reclaimPolicy: Delete in StorageClass definitions for non-critical data, audit PVs and load balancers quarterly, tag GKE-managed resources with managed-by: gke labels for tracking.

Oversized GPU nodes running underutilized

GPU nodes (n1-standard-4 + T4 GPU) cost about $0.54/hour — roughly 3x more than the CPU-only VM. Teams often provision GPU node pools with min: 1 for ML workloads that run 2-3 hours/day, paying for 21 hours of idle GPU time daily (~$11/day waste per node).

Optimization: Use Cluster Autoscaler with min: 0 for GPU pools (accept 60-90 second cold-start for node provisioning), schedule GPU workloads during batch windows to consolidate usage, or switch to GKE Autopilot with GPU pods that scale to zero when idle.

Right-Sizing Pods and Node Pools

GKE cost optimization starts with aligning pod requests to actual usage and choosing machine types that pack efficiently.

Setting requests and limits from real utilization data

Pod resource requests guarantee capacity (Kubernetes won't schedule the pod without it), while limits cap maximum consumption (CPU throttling kicks in at limit, memory exceeding limit triggers OOMKill). Most teams set requests = limits, which prevents burst capacity and forces over-provisioning.

Recommended approach:1. Deploy VPA in recommendation mode — updateMode: "Off" collects metrics without applying changes2. Wait 7-14 days for usage histogram stabilization (VPA polls metrics-server every 60 seconds)3. Review recommendations — kubectl describe vpa <name> shows target requests at ~90th percentile4. Set requests at 95th percentile, limits at 150-200% of requests — allows burst without waste

Example: A Python API service with VPA recommendations:

  • Current: requests=1 vCPU, limits=1 vCPU, actual usage 0.2-0.4 vCPU
  • VPA recommendation: requests=0.4 vCPU (90th percentile)
  • Optimized config: requests=0.5 vCPU (95th + margin), limits=1 vCPU (allows 2x burst)

This configuration uses 50% of original request (saves money) while allowing 2x burst capacity for traffic spikes (prevents throttling).

Realistic utilization targets and how much headroom to leave

Kubernetes best practices recommend 60-80% average CPU utilization and 50-70% memory utilization. Lower targets (30-40%) waste capacity; higher targets (>85%) risk pod evictions and performance degradation during bursts.

Headroom calculation:

  • Planned growth: If traffic grows 20% annually, size node pools at 75% current utilization to accommodate 12-18 months of growth before re-scaling
  • Traffic variance: Measure weekly peak-to-trough ratio; if peaks are 3x trough, target 50-60% utilization at trough (allows 3x scale-up without emergency node provisioning)
  • Deployment churn: Rolling updates can temporarily increase pod count according to maxSurge — 25% by default. Maintain 20-30% headroom, adjusted for your configured maxSurge, termination grace period, and deployment behavior, to absorb releases without triggering Cluster Autoscaler every time

For cost-sensitive workloads (dev, staging), push utilization to 80-85%. For production, maintain 65-70% to balance cost and reliability.

Choosing machine types for bin-packing efficiency

Machine type selection determines bin-packing density and workload fit. Larger nodes (8+ vCPU) can improve packing efficiency and reduce per-node system overhead but have a higher blast radius (one node failure affects more pods); smaller nodes (2-4 vCPU) improve failure isolation but add ~5% overhead per node for kubelet and system daemons.

Machine type trade-offs (us-central1, 2026):

Family

vCPU:Memory

Monthly cost (4 vCPU)

Best for

e2-standard-4

1:4 (4 vCPU, 16 GiB)

$119.72

General web services, APIs (lowest cost)

n2-standard-4

1:4 (4 vCPU, 16 GiB)

$141.62

Mixed workloads, eligible for SUDs (sustained use discounts)

c2-standard-4

1:2 (4 vCPU, 8 GiB)

~$180

Compute-bound (video encoding, data processing)

n2-highmem-4

1:8 (4 vCPU, 32 GiB)

~$195

Memory-heavy (Redis, Spark, in-memory databases)

Decision framework:

  • Start with e2-standard-4 for general workloads (lowest cost, sufficient for 80% of use cases)
  • Compare E2 with N2 after sustained use discounts — N2 begins earning SUDs after 25% of the month and can reach up to a 20% effective monthly discount; compare the resulting effective price rather than assuming N2 is cheaper
  • Use c2-standard for proven CPU-bound workloads (profiling shows >80% CPU, <50% memory utilization)
  • Reserve n2-highmem for memory:CPU ratio >4:1 (databases, caches, analytics engines)

For bin-packing, standardize on 2-3 machine types per cluster — mixing 10+ machine types fragments node pools and complicates autoscaling.

Separating workloads into purpose-built node pools

Single-pool clusters force all workloads to share nodes, creating resource contention and preventing targeted optimization (e.g., using spot nodes for batch workloads only). Multi-pool architecture isolates workload classes and optimizes each independently.

Recommended node pool structure:

Pool name

Machine type

Min/Max nodes

Spot/preemptible

Workload type

production

n2-standard-4

2/10

No

Customer-facing services

batch

c2-standard-8

0/20

Yes (100%)

CI/CD, ETL, ML training

stateful

n2-highmem-4

1/5

No

Databases, queues, caches

system

e2-small

1/2

No

kube-system pods only

Isolation via taints and tolerations: Tag batch pool with workload-type=batch:NoSchedule, add tolerations to batch pods. This prevents production pods from landing on preemptible nodes during capacity crunches (which would cause service disruptions when spot nodes are reclaimed).

Benefit: Batch pool runs on spot (60-80% discount), production pool uses on-demand or CUD-backed capacity (predictable cost), stateful pool uses local SSD for performance. Each pool autoscales independently — batch can scale to 20 nodes during CI runs without affecting production stability.

Getting the Autoscaler Stack Right

GKE provides four autoscaling mechanisms: HPA (pod replicas), VPA (pod resource requests), Cluster Autoscaler (node count), and Node Auto-Provisioning (machine types). These systems interact — HPA scales up replicas, triggering Cluster Autoscaler to add nodes. Misconfiguration causes cost blowouts (over-scaling) or performance degradation (slow scale-up).

Horizontal Pod Autoscaler

HPA scales pod replicas based on CPU/memory utilization metrics reported by metrics-server. When average utilization across all pods exceeds the target (e.g., 70% CPU), HPA increases replica count proportionally.

Configuration example:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Target tuning: A 2024 Google Cloud study tested HPA with 50% vs 70% CPU targets. The 50% target provided better p99 latency but "led to an imbalance between cost and performance" — 40% more replicas for the same throughput.

The recommendation is to set HPA target at 70-75% for cost-sensitive workloads, 50-60% for latency-sensitive services (p99 <100ms SLA).

Vertical Pod Autoscaler

VPA adjusts pod resource requests based on observed usage. Unlike HPA (which scales replicas), VPA changes the CPU/memory requests of existing pods. VPA operates in several modes:

  • "Off" — recommendation only (safe for production)
  • "Initial" — sets requests on pod creation, never updates running pods
  • "Auto" / "Recreate" — applies updated requests by recreating pods
  • "InPlaceOrRecreate" — attempts to resize pods in place and falls back to recreation when necessary

When to use VPA: For stateful workloads that cannot scale horizontally (databases, caches), or for long-running batch jobs where right-sizing requests matters more than replica count.

When NOT to use VPA: Avoid using VPA and HPA on the same CPU or memory metrics. They can coexist when HPA scales on custom or external metrics, or through GKE's multidimensional Pod autoscaling.

Cluster Autoscaler

Cluster Autoscaler provisions new nodes when pods are unschedulable due to insufficient cluster capacity, and removes underutilized nodes when they can be safely consolidated. It evaluates the cluster regularly and acts when:

  • Scale-up: Pods are unschedulable because the cluster lacks capacity
  • Scale-down: Nodes remain underutilized long enough to be removed without violating scheduling constraints or PodDisruptionBudgets

Cost optimization setting: GKE exposes autoscaling profiles rather than the upstream Cluster Autoscaler flags directly. The default balanced profile prioritizes a balance between cost and availability; optimize-utilization scales down more aggressively to improve utilization.

```bashgcloud container clusters update CLUSTER_NAME --autoscaling-profile optimize-utilization --location=LOCATION```

Node Auto-Provisioning

Node Auto-Provisioning (NAP) automatically creates new node pools with machine types optimized for pending pods' resource requests. Instead of pre-defining node pools, NAP provisions e2-standard-4 for small pods, n2-highmem-16 for memory-heavy pods, etc.

When NAP makes sense: Multi-tenant clusters running diverse workloads (data science platform, CI/CD, web services) where pre-defining every node pool is impractical.

Auto-created node pools normally scale down and are deleted when empty. Pools that are excluded from node-pool auto-creation or manually managed do not receive that same automatic lifecycle behavior.

How they interact — and where HPA and VPA conflict on the same metric

HPA and VPA can run on the same cluster, but avoid targeting the same workload with overlapping CPU or memory metrics. The conflict can look like this:

  1. HPA sees 70% CPU utilization, scales from 3 to 6 replicas
  2. Per-pod CPU drops to 35% if the same total load is spread across twice as many replicas
  3. VPA observes lower per-pod CPU and may recommend cutting requests (for example, 0.5 vCPU → 0.25 vCPU)
  4. If you apply the VPA recommendation, the CPU utilization percentage used by HPA rises again because the requests dropped, even though actual workload demand has not increased
  5. Repeated automated adjustments to requests and replica counts can create unstable scaling behavior and unnecessary resource consumption

The solution is to use HPA for CPU-based horizontal scaling and VPA in recommendation mode only (updateMode: "Off") when both operate on the same workload and CPU/memory signals. Apply VPA recommendations manually during regular maintenance windows rather than automatically. VPA and HPA can also coexist when HPA scales on custom or external metrics instead of the same CPU or memory signals VPA is adjusting.

Spot VMs and Discount Mechanics

Spot VMs offer 60-80% discounts but can be reclaimed with 30 seconds' notice. Mixing spot, on-demand, and committed capacity requires careful orchestration to balance cost and reliability.

Spot node pools for fault-tolerant workloads, and graceful handling of preemption

Spot nodes work for workloads that tolerate interruption: CI/CD runners, data pipelines (with checkpointing), ML training (with periodic snapshots), and stateless web services with ≥3 replicas. You may wonder if you can bring down egress costs by placing all pods onto the same node or at least nodes within the same zone?" While zone consolidation reduces egress, it also concentrates risk — a zonal outage takes down the entire service.

Spot node best practices:

1. Set PodDisruptionBudgets for voluntary disruptions — PDBs help protect workloads during drains and autoscaler scale-down, but they do not prevent involuntary Spot reclamation. If your capacity plan assumes tolerating 30-40% Spot loss, maintain enough replicas and fallback capacity to absorb that loss rather than relying on the PDB.

2. Mix spot and on-demand — 70% spot, 30% on-demand in the same cluster (via separate node pools with shared labels)

3. Use node affinity to prefer spot — preferredDuringSchedulingIgnoredDuringExecution with weight=100 for cloud.google.com/gke-spot: "true" nodes

Graceful preemption handling: Spot nodes have a default 30-second graceful node shutdown period. By default, regular pods receive up to the first 15 seconds to terminate, followed by 15 seconds for critical system pods. Configure pods with:

  • terminationGracePeriodSeconds — keep this within the shutdown time actually available to the pod; requesting more time does not extend the underlying Spot shutdown window
  • preStop hook to deregister from load balancer or flush in-memory state
  • Liveness/readiness probes with failureThreshold: 1 (fast detection of unhealthy pods during preemption)

CUDs applied to GKE

Google Cloud offers two main commitment models relevant to GKE:

Resource-based Compute Engine CUDs commit to eligible vCPU and memory resources in a region. For common general-purpose families such as N2, discounts can reach 37% for 1 year and 55% for 3 years. These primarily apply to the underlying Compute Engine nodes used by GKE Standard.

Compute Flexible CUDs are spend-based commitments that can apply across eligible GKE, Compute Engine, and Cloud Run usage. Eligible GKE Standard and Autopilot usage receives 28% off with a 1-year commitment or 46% with a 3-year commitment.

For Compute Flexible CUDs, the simple on-demand break-even is approximately 72% utilization for a 1-year commitment and 54% for a 3-year commitment. Resource-based CUD break-even varies with the applicable discount and machine family.

Operating commitments underneath an autoscaling node pool without stranding them

The challenge with resource-based CUDs: Cluster Autoscaler scales node count dynamically (3 nodes at night, 15 nodes during business hours), but resource-based CUDs commit to fixed capacity (e.g., capacity equivalent to 10 n2-standard-4 nodes).

Strategies:

1. Set min node count = CUD capacity — if your baseline is 10 nodes and you commit to that capacity via CUD, set the node pool minimum to 10 nodes. Cluster Autoscaler cannot scale below the configured minimum

2. Right-size CUD to baseline, not peak — measure 30-day minimum node count (the floor, not the average). Commit to that baseline via CUD, let autoscaler handle bursts with on-demand

3, Use flexible CUDs — Compute Flexible CUDs are spend-based and can apply across eligible GKE, Compute Engine, and Cloud Run usage. They provide 28% off for a 1-year commitment and 46% off for a 3-year commitment, compared with roughly 37% and 55% for N2 resource-based CUDs.

Mixing Spot, on-demand and committed capacity in one cluster

Architecture: Create 3 separate node pools targeting the same workload labels:

1. CUD pool — n2-standard-4, min=8, max=8 (no autoscaling), backed by 3-year CUD

2. On-demand pool — n2-standard-4, min=0, max=5, no spot (handles burst above CUD capacity)

3. Spot pool — n2-standard-4, min=0, max=10, 100% spot (handles additional burst, cost-optimized)

Pod placement priority: Use pod priority classes:

  • High priority (1000) →lands on baseline or on-demand nodes (via affinity)
  • Low priority (100) → prefers spot (via affinity), falls back to on-demand if spot unavailable

CUD credits apply at the billing layer to eligible non-Spot usage; they do not attach to a particular Kubernetes node pool. Baseline usage can therefore receive applicable CUD discounts while Spot handles fault-tolerant burst capacity and on-demand nodes provide fallback.

Visibility and Attribution

Cost allocation surfaces which teams, applications, or customers drive GKE spend, enabling chargeback and optimization prioritization.

GKE cost allocation by namespace, workload and team

For Standard clusters, GKE cost allocation can add cluster, namespace, workload type, workload name, and Kubernetes label dimensions to the detailed Cloud Billing export in BigQuery.

Label-based allocation:

1. Tag node pools — add labels: team=platform, env=production, cost-center=engineering

2. Propagate to GCP resources — node labels auto-propagate to underlying Compute Engine VMs (visible in GCP billing export)

3. Query billing data — BigQuery join on labels.team to aggregate cost by team

The limitation is that GKE cost allocation is based on resource requests, not actual resource consumption. Shared or unallocated overhead and unsupported SKUs can also remain unattributed.

Cost-related optimization metrics in GKE

GKE exposes cost optimization metrics in Cloud Monitoring:

  • CPU request utilization — actual CPU usage / CPU requests (target 60-80%)
  • Memory request utilization — actual memory / memory requests (target 50-70%)
  • Node count over time — detect idle node pools or slow scale-down
  • Pod scheduling failures — unschedulable pods indicate under-provisioning

Alert thresholds:

  • CPU request util <40% for >7 days → pods over-requesting, right-size
  • Node count >50% above 30-day average → check for stuck nodes or missing scale-down
  • >10 pod scheduling failures/hour → cluster under-provisioned, scale up

These metrics do NOT show cost per namespace or team — only cluster-wide resource efficiency.

Native tooling vs what you still have to build

GCP native capabilities:

  • Cluster-level cost in billing console
  • Node pool cost (via labeled VMs)
  • Cost optimization metrics (utilization, inefficiency)
  • Namespace and workload cost allocation through GKE cost allocation and detailed billing export
  • Kubernetes-label dimensions for allocation

What you build:

  • Idle resource detection — query for Released PVs, unused load balancers, orphaned disks
  • Commitment utilization — compare CUD capacity to actual node hours, flag underutilization

For clusters >100 pods or multi-tenant environments, consider tools like Kubecost or OpenCost that provide pod-level cost breakdowns. For nOps coverage of these tools, see Kubecost vs OpenCost comparison.

Automatically Reduce Your GKE Costs with nOps

nOps was built to help you understand and reduce your cloud costs with:

  • Real-Time Cost Visibility & Detailed Cost Allocation: Track, allocate, and report on GKE spend alongside your other Google Cloud services, AWS, Azure, SaaS, Kubernetes, and AI costs in a single pane of glass.
  • Anomaly Detection: Get alerted when GKE or related spend increases unexpectedly, whether from runaway autoscaling, higher replica counts, oversized CPU and memory requests, additional nodes, increased request volume, networking, logging, or other cost drivers.
  • Automated Commitment Management: nOps automatically manages GCP commitments to maximize savings and flexibility across your broader GCP environment. Potential savings are often 20% higher than competitors.

Curious how optimized you are on Google Cloud Platform? A 30-minute free savings analysis shows you your current Effective Savings Rate and where the opportunities are. Setup is 5 minutes with no agents or infra changes needed.

nOps manages $5 billion in cloud spend for its customers and is rated 5 stars on G2.

Demo

AI-Powered Cost Management Platform

Discover how much you can save in just 10 minutes!

Book a Demo
Demo

FAQ

kubectl describe vpa --all-namespaces | grep -A5 "Recommendation"

Compare recommended CPU/memory to current requests. Pods with current >2x recommended are top candidates for right-sizing.

CUDs require 1-year or 3-year commitments. Break-even:

  • 1-year Compute Flexible CUD (28% discount): simple on-demand break-even is roughly 72% utilization
  • 3-year Compute Flexible CUD (46% discount): simple on-demand break-even is roughly 54% utilization
  • Resource-based CUDs: for common general-purpose machine families with roughly 37%/55% discounts, the simple equivalents are roughly 63%/45%, respectively
Should I use Autopilot or Standard mode for a new GKE cluster?

Start with Autopilot if your team lacks Kubernetes expertise or if workloads are highly variable (pod counts swing 2-3x daily). Switch to Standard once you have 20+ nodes, predictable traffic patterns, and engineering capacity to manage node pools. Standard mode can be 15-30% cheaper at scale with proper bin-packing and committed use discounts, but only if actively optimized.

How do I prevent HPA and Cluster Autoscaler from fighting each other?

Set HPA minReplicas above zero (e.g., minReplicas: 3) to prevent scale-to-zero. For node scale-down behavior, use GKE's supported autoscaling profiles rather than configuring scale-down-delay-after-add directly. Avoid using VPA in update mode on the same CPU or memory metrics HPA uses; they can coexist when HPA scales on custom or external metrics.

Can I use spot nodes for production workloads?

Yes, but only for stateless services with ≥3 replicas and loose latency SLAs (p99 >500ms). Use PodDisruptionBudgets for voluntary disruptions, but plan separately for Spot reclamation with enough replicas and a 30-40% on-demand buffer. Monitor spot reclamation rate in Cloud Logging (gce_instance resource, compute.instances.preempted event).

What's the fastest way to cut GKE costs by 20% this month?

Pricing is one of the biggest levers. Eligible GKE spend can be covered by Google Cloud committed use discounts (CUDs), but the challenge is matching commitments to an environment where node counts and usage can change constantly. nOps manages this layer by analyzing historical spend and forecasted demand, recalculating optimal coverage hourly, and adding commitments in small increments rather than relying on large, infrequent purchases.

How do I find overprovisioned pods?

Deploy VPA in recommendation mode (`updateMode: "Off"`), wait 7 days, run: ```bash kubectl describe vpa --all-namespaces | grep -A5 "Recommendation" Compare recommended CPU/memory to current requests. Pods with current >2x recommended are top candidates for right-sizing.

Does GKE charge for stopped nodes?

Stopped nodes incur $0 VM usage charges. However, the cluster management fee and attached resources can continue to incur charges. Persistent disks attached to stopped nodes continue to cost about $0.04/GiB-month for Standard PD or $0.17/GiB-month for SSD PD in us-central1.

What's the break-even point for committed use discounts (CUDs) on GKE?

CUDs require 1-year or 3-year commitments. Break-even: 1-year Compute Flexible CUD (28% discount): simple on-demand break-even is roughly 72% utilization 3-year Compute Flexible CUD (46% discount): simple on-demand break-even is roughly 54% utilization Resource-based CUDs: for common general-purpose machine families with roughly 37%/55% discounts, the simple equivalents are roughly 63%/45%, respectively

Tags

Shouri Thallam

Shouri Thallam

Published Date: September 5, 2026, Google Cloud Platform (GCP)

Related Posts

Google Cost Optimization: The Ultimate Guide for 2026

Google Cloud Platform (GCP)

Google Cost Optimization: The Ultimate Guide for 2026

bynOpsnOpsPublished Date: Sep 7, 2026
GCP Orphaned Resources: How to Find and Safely Clean Up Cloud Waste

Google Cloud Platform (GCP)

GCP Orphaned Resources: How to Find and Safely Clean Up Cloud Waste

bynOpsnOpsPublished Date: Sep 4, 2026
GCP Egress Costs Explained: Pricing Tiers, Hidden Charges and How to Cut Them

Google Cloud Platform (GCP)

GCP Egress Costs Explained: Pricing Tiers, Hidden Charges and How to Cut Them

byChintu ParikhChintu ParikhPublished Date: Sep 3, 2026
GCP Right-Sizing Guide: How to Match Compute Engine VMs to Real Demand

Google Cloud Platform (GCP)

GCP Right-Sizing Guide: How to Match Compute Engine VMs to Real Demand

bynOpsnOpsPublished Date: Sep 2, 2026
GCP Right-Sizing Guide: How to Match Compute Engine VMs to Real Demand

Google Cloud Platform (GCP)

GCP Right-Sizing Guide: How to Match Compute Engine VMs to Real Demand

bynOpsnOpsPublished Date: Sep 2, 2026
Google Cloud Storage Pricing 2026: Full Cost Breakdown by Storage Class

Google Cloud Platform (GCP)

Google Cloud Storage Pricing 2026: Full Cost Breakdown by Storage Class

byRaj GangulyRaj GangulyPublished Date: Sep 1, 2026