Troubleshooting GKE Cluster Autoscaler Scale-Up Blockers: A Complete Guide
The GKE Cluster Autoscaler fails to scale up when pending Pods cannot be matched to available node capacity due to resource constraints, quota limits, ComputeClass mismatches, or stale reservation caches.
The GKE Cluster Autoscaler (CA) is a core Kubernetes component that continuously monitors pending Pods and evaluates whether to expand existing node pools or provision new ones through Node Auto-Provisioning (NAP). When scale-up doesn't occur as expected, the CA emits specific messageId events that pinpoint the root cause. This guide walks through systematic troubleshooting based on the google/skills repository's authoritative debugging resources.
Understanding the GKE Cluster Autoscaler Architecture
Before diving into troubleshooting, it's essential to understand how the CA interacts with related components according to the source analysis.
Key Components Involved in Scale-Up Decisions
| Component | Role in Scale-Up |
|---|---|
| Cluster Autoscaler | Reads pending Pods, evaluates ComputeClass limits, quota, reservations, and node-pool settings |
| Node Auto-Provisioning (NAP) | Creates brand-new node pools on-the-fly when existing pools cannot satisfy requests |
| ComputeClass | Declarative resource defining allowed machine families, zones, and optional reservation blocks |
| Reservations | Pre-allocated capacity CA can target; subject to 30-minute cache staleness |
| Quotas & Committed Use Discounts (CUDs) | Project-level limits CA respects automatically |
| Pod-Level Selectors | Labels like cloud.google.com/machine-family and gke-spot that must match ComputeClass configuration |
Common GKE Cluster Autoscaler Scale-Up Blockers
The CA emits diagnostic messageId values that directly explain why a scale-up request was rejected. Here are the most frequent blockers found in GKE production clusters.
Resource and Infrastructure Blockers
messageId |
Root Cause | Resolution |
|---|---|---|
scale.up.error.out.of.resources |
GCE stock-out in requested zone/machine family | Add fallback zones/families in ComputeClass configuration |
scale.up.error.quota.exceeded |
Project quota limit reached | Request higher regional quota in Google Cloud Console |
scale.up.error.ip.space.exhausted |
Subnet IP address pool exhausted | Expand the Pod IP CIDR range |
Configuration and Policy Blockers
messageId |
Root Cause | Resolution |
|---|---|---|
scale.up.no.scale.up |
No ComputeClass priority matches Pod resource requests | Verify Pod resource requests and selectors align with ComputeClass |
scale.up.error.reservation.stale |
CA cache hasn't synced new reservation (created < 30 min ago) | Wait ≥30 minutes after reservation creation before relying on it |
The 30-minute reservation cache lag is a particularly subtle blocker documented in skills/cloud/gke-cluster-autoscaler/references/ca-optimization.md. The CA maintains an internal cache of available reservations that refreshes periodically; newly created reservations are invisible to scale-up decisions until this cache synchronizes.
Step-by-Step Debugging Workflow
Follow this systematic approach to diagnose GKE Cluster Autoscaler scale-up failures using scripts and commands from the google/skills repository.
Step 1: Stream Live Autoscaler Events
The repository provides assets/log-autoscaler-events.sh for real-time visibility into CA decisions:
./assets/log-autoscaler-events.sh <cluster-name>
This script tails the Cluster Autoscaler's visibility logs, exposing noDecisionStatus.noScaleUp fields that contain the exact messageId and rejection reason.
Step 2: Inspect the Pending Pod
Examine why Kubernetes cannot schedule the Pod:
kubectl describe pod <pod-name>
Look for events indicating:
Insufficient cpuInsufficient memorynode(s) had taints that the pod didn't toleratenode(s) didn't match Pod's node affinity/selector
Step 3: Run the Pending Pod Checklist
From skills/cloud/gke-cluster-autoscaler/references/ca-debug.md, verify these common misconfigurations:
--max-nodeslimits are not hit on target node pools- Selector conflicts are absent (e.g.,
gke-spot=truelabel on a Pod targeting an On-Demand ComputeClass) - Node pool auto-creation is enabled:
nodePoolAutoCreation.enabled: true - The exact
noDecisionStatus.noScaleUpreason is identified in visibility logs
Step 4: Check for Reservation Cache Lag
If your workload depends on a recently created reservation:
# Verify reservation creation timestamp
gcloud compute reservations describe <reservation-name> --zone=<zone> \
--format='table(name,creationTimestamp)'
If created within ~30 minutes, delay scale-up testing until the CA cache refreshes. This behavior is explicitly documented in the CA optimization reference.
Step 5: Identify Scale-Down Blockers (If CA Appears Stuck)
Run the helper script to detect why nodes might be retained:
./assets/find-scale-down-blockers.sh
Common scale-down blockers include:
- Bare Pods (not managed by a controller)
- Local storage (
emptyDiron SSD, persistent local volumes) cluster-autoscaler.kubernetes.io/safe-to-evict: "false"annotations- PodDisruptionBudgets with
maxUnavailable: 0orminAvailableequal to replica count - Non-zero
min-nodesfloor on the node pool
Step 6: Performance Tuning for Sluggish Scale-Up
If CA responds slowly but eventually scales:
# Reduce node pool count ( >200 pools degrades CA performance)
# Prefer 'preferred' anti-affinity over 'required' anti-affinity
# Use topologySpreadConstraints instead of hard anti-affinity where possible
# Increase Spot node graceful shutdown period
kubectl patch nodeconfig default -n gke-managed-system \
--type=merge -p '{"spec":{"shutdownGracePeriodSeconds":120}}'
Practical Code Reference
Essential Diagnostic Commands
# Stream live autoscaler events
assets/log-autoscaler-events.sh my-gke-cluster
# Show why a Pod cannot be scheduled
kubectl describe pod my-app-5678
# Look for: "Insufficient cpu", "node(s) had taints", etc.
# Verify node pool limits aren't blocking scale-up
kubectl get nodepool my-pool -o yaml | grep -A2 maxNodes
# Enable node pool auto-creation if disabled
kubectl patch nodepool my-pool \
--type=merge -p '{"spec":{"nodePoolAutoCreation":{"enabled":true}}}'
# Segregate system Pods to dedicated pool
kubectl label ns kube-system \
cloud.google.com/default-compute-class-non-daemonset=system-pool
# Manually clean up stale VMs when CA is stuck at min-nodes = 0
gcloud compute instances delete <stale-instance> --zone=<zone>
Key Source Files in google/skills
| File Path | Purpose |
|---|---|
skills/cloud/gke-cluster-autoscaler/references/ca-debug.md |
Complete messageId cheat-sheet, pending Pod checklist, live visibility scripts |
skills/cloud/gke-cluster-autoscaler/references/ca-optimization.md |
Capacity buffer tuning, reservation cache lag documentation, optimization profiles |
skills/cloud/gke-cluster-autoscaler/references/ca-provisioning.md |
ComputeClass provisioning, fallback policies, NAP configuration |
skills/cloud/gke-cluster-autoscaler/SKILL.md |
High-level Autoscaler overview, terminology, best practices |
skills/cloud/cloud-logging-query-generation/references/query_gke.md |
Pre-built Cloud Logging queries for Autoscaler event analysis |
assets/log-autoscaler-events.sh |
Real-time CA log streaming script |
assets/find-scale-down-blockers.sh |
Automated scan for scale-down blocking conditions |
Summary
- Decode
messageIdvalues from CA visibility logs to immediately identify scale-up blockers: resource exhaustion, quota limits, IP exhaustion, or ComputeClass mismatches - Account for 30-minute reservation cache lag when testing newly created reservations for scale-up
- Use
assets/log-autoscaler-events.shfor live debugging andassets/find-scale-down-blockers.shfor cleanup analysis - Verify Pod selectors align with ComputeClass definitions, especially for
gke-spotand machine-family constraints - Reference
ca-debug.mdandca-optimization.mdfrom the google/skills repository for authoritative troubleshooting procedures
Frequently Asked Questions
How do I know if the Cluster Autoscaler is even running?
Check for the cluster-autoscaler deployment in the kube-system namespace:
kubectl get deployment cluster-autoscaler -n kube-system
If present and running, examine its logs with kubectl logs -n kube-system deployment/cluster-autoscaler. The assets/log-autoscaler-events.sh script provides a higher-level view specifically designed for scale-up visibility.
Why does my reservation not trigger scale-up immediately?
The GKE Cluster Autoscaler maintains a 30-minute internal cache for reservation availability as implemented in the CA's capacity planning layer. Reservations created more recently are not visible to scale-up decisions until this cache refreshes. Wait at least 30 minutes after reservation creation before expecting CA to target it, or check ca-optimization.md for cache refresh behavior details.
What is the difference between scale-up and Node Auto-Provisioning?
Scale-up expands an existing node pool by adding nodes. Node Auto-Provisioning (NAP) creates an entirely new node pool when no existing pool matches the Pod's requirements. NAP requires nodePoolAutoCreation.enabled: true in the node pool or cluster configuration. NAP decisions appear in visibility logs with distinct provisioning events.
How can I tell if quota is blocking my scale-up?
Search CA visibility logs for scale.up.error.quota.exceeded. The specific quota type (CPUs, in-use addresses, SSD total capacity) appears in the event details. Alternatively, run:
gcloud compute project-info describe --project <project-id>
to inspect current quota usage against limits, then request increases in the Google Cloud Console IAM & Admin > Quotas section.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →