Troubleshoot GKE TPU reservation stockouts caused by leaked node pool capacity
Use this skill to diagnose and resolve GKE TPU node pool creation or scale-up
failures that fail with GCE_STOCKOUT, ZONE_RESOURCE_POOL_EXHAUSTED, or
ZONE_RESOURCE_POOL_EXHAUSTED_WITH_DETAILS (or queue due to lack of capacity)
even though they target a specific Compute Engine TPU reservation.
If node auto-repair is disabled on an existing TPU node pool, GKE doesn't repair
its nodes when they become NotReady. While their VMs are still running, they
keep consuming slots in the reservation (inUseCount is the number of running
instances that consume the reservation). Per
Ensure reservation availability,
the reservation must have sufficient available TPU chips at the time of node
pool creation, and per
Multi-host TPU slice node pools,
if GKE is unable to deploy one node in a slice, no nodes in the TPU slice node
pool are deployed. When the free slots in the reservation
(specificReservation.count - specificReservation.inUseCount; see
Consumable instances in a reservation)
are fewer than the number of nodes that the new TPU node pool needs, creation
fails with GCE_STOCKOUT or ZONE_RESOURCE_POOL_EXHAUSTED (or queues due to
lack of capacity).
Attribution
MUST READ: Before executing any gcloud, REST API, or MCP command, you
MUST read Usage Attribution. For commands executed
directly in the terminal (never in generated scripts, Terraform, or user code),
prefix gcloud with
CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:gke-ai-troubleshooting-tpu-reservation-stockout)"
and append agent-skills/1.0 (skill:gke-ai-troubleshooting-tpu-reservation-stockout) to User-Agent headers.
Prerequisites
- Required IAM Roles:
- Logs Viewer (
roles/logging.viewer): Query Cloud Audit Logs in Cloud
Logging.
- Monitoring Viewer (
roles/monitoring.viewer): Query GKE node readiness
metrics in Cloud Monitoring.
- Kubernetes Engine Viewer (
roles/container.viewer): Inspect GKE node pools
(management.autoRepair), cluster operations, and node conditions.
- Compute Viewer (
roles/compute.viewer): Inspect Compute Engine reservation
utilization (specificReservation.inUseCount vs
specificReservation.count), consuming instances, and VM labels (including
in the reservation's owner project if using a shared reservation).
- For remediation (
[High Risk] steps): Kubernetes Engine Cluster Admin
(roles/container.clusterAdmin)
- API Enablement & Billing:
- Ensure the target project has an active Google Cloud billing account
attached:
gcloud billing projects describe {project_id}.
- Enable required APIs:
container.googleapis.com, compute.googleapis.com,
logging.googleapis.com, and monitoring.googleapis.com.
- CLI & Authentication Setup:
- Cluster mode: This skill applies to Standard clusters. Autopilot clusters
always auto-repair nodes, and you can't turn this off (see
Settings for Autopilot and Standard).
- Reference Documentation:
- Auto-repair nodes
(Sections: "Settings for Autopilot and Standard", "Repair criteria", "Node
repair process", "Verify node auto-repair is enabled for a Standard node
pool", "Node auto repair in TPU slice nodes", "Enable auto-repair for an
existing Standard node pool", "Get information about recent automated repair
events")
- Troubleshoot GKE Standard node pools
(Sections: "Issue: Node pool creation fails due to insufficient resources")
- Troubleshoot TPUs in GKE
(Sections: "How GKE handles capacity issues", "Insufficient TPU resources to
satisfy the TPU request")
- About TPUs in GKE
(Sections: "Multi-host TPU slice node pools")
- Consuming reserved zonal resources
(Sections: "Consuming a specific shared reservation")
- About reservations
(Sections: "How reservations work")
- View reservations or future reservation requests
(Sections: "Limitations", "View reservations", "Consumable instances in a
reservation", "View a list of instances that are consuming a reservation")
- Organize resources using labels
(Sections: "View labels")
- Create and manage cluster and node pool labels
(Sections: "Automatically applied labels")
- Deploy TPU workloads in GKE Standard
(Sections: "Ensure reservation availability", "Monitor health metrics for
TPU nodes and node pools", "Configure auto repair for TPU slice nodes")
- Add and manage node pools
(Sections: "Delete a node pool")
Read-only rule: Run read-only diagnostic commands only. Never drain,
delete, or re-create nodes, or run any other command that changes the cluster.
Give the user any fix to apply themselves.
When you recommend a fix, link the doc section that describes it.
Diagnostic workflow
Step 0: Collect context and set the investigation window
Identify the following environment parameters from the user prompt or cluster
context:
{project_id}, {cluster_name}, {location}, {failing_nodepool_name},
{reservation_name}, {reservation_project_id} (the project that owns
{reservation_name}, which defaults to {project_id} for a single-project
reservation or is the owner project for a shared reservation; see
Consuming a specific shared reservation),
{zone} (the zone of the reservation), and {issue_time}.
- Time window: By default, query a 60-minute window
[{issue_time} - 30m, {issue_time} + 30m] ({start_time} to {end_time}).
Step 1: Confirm the stockout error and reservation utilization [Low Risk]
- Check Cloud Audit Logs and GKE operations for stockout or capacity
errors:
- Check Compute Engine reservation utilization:
- Per
Limitations,
query shared reservations in the owner project where they were created
(
{reservation_project_id}).
- Follow the
View reservations
section to run
gcloud compute reservations describe {reservation_name} --zone={zone} --project={reservation_project_id} or gcloud compute reservations list --project={reservation_project_id}, and compare
specificReservation.inUseCount against specificReservation.count.
Interpret the results
- Don't suggest deleting any node pool until you have identified which existing
VMs and node pools hold the reserved capacity (Step 2).
- Stockout confirmed: Per
Ensure reservation availability
and
Multi-host TPU slice node pools,
if GKE can't deploy one node in a multi-host slice, no nodes in the slice are
deployed. If a stockout or lack-of-capacity message is present and the free
slots (
specificReservation.count - specificReservation.inUseCount; see
Consumable instances in a reservation)
are fewer than the number of nodes that {failing_nodepool_name} needs,
proceed to Step 2.
Step 2: Find which VMs and node pools hold the reservation [Low Risk]
- Check which VMs are consuming
{reservation_name}:
- Check node readiness in
{cluster_name}:
- Query the Cloud Monitoring metric
kubernetes_io:node_status_condition
(monitored_resource="k8s_node", cluster_name="{cluster_name}",
condition="Ready") described in
Monitor health metrics for TPU nodes and node pools.
The status label value is True, False, or Unknown (capitalized);
use status!="True" to find nodes whose Ready condition is False or
Unknown.
- List TPU nodes and their node pool labels with
kubectl get nodes -l cloud.google.com/gke-tpu-accelerator -L cloud.google.com/gke-nodepool.
- Exclude the failing node pool: Leave
{failing_nodepool_name} out of the
unhealthy list. It's the node pool that couldn't get capacity, not the one
holding it.
Interpret the results
- VMs outside
{cluster_name}: If some of the VMs consuming
{reservation_name} aren't nodes in {cluster_name} (for example, their
labels show another GKE cluster or they are Compute Engine VMs without GKE
labels), tell the user which VMs or other clusters hold those reservation
slots.
- Fewer listed VMs than
specificReservation.inUseCount: Per
View a list of instances that are consuming a reservation,
the list only includes VMs in one project. If the list has fewer VMs than
specificReservation.inUseCount, tell the user that VMs in other projects
that share {reservation_name} are consuming the remaining slots.
- Unhealthy node pool in
{cluster_name} ({leaking_nodepool_name}): If
the VMs consuming {reservation_name} belong to an existing NotReady node
pool in {cluster_name} ({leaking_nodepool_name}), proceed to Step 3.
- Healthy reservation (rule out a leak): If the reserved slots are held by
healthy, in-use node pools, there is no leak. Explain that healthy node pools
hold the reserved slots, so too few slots are free for
{failing_nodepool_name}. Tell the user not to delete or restart those
healthy node pools, and point the user to the consumption options in
Insufficient TPU resources to satisfy the TPU request.
Step 3: Verify node auto-repair on the leaking node pool [Low Risk]
Follow
Verify node auto-repair is enabled for a Standard node pool
for {leaking_nodepool_name}:
- Auto-repair is disabled (
management.autoRepair: false): GKE doesn't
repair the NotReady nodes in {leaking_nodepool_name}. Their running VMs
keep counting toward specificReservation.inUseCount in {reservation_name},
so {failing_nodepool_name} can't get reserved capacity. Proceed to Step 4.
- Auto-repair is enabled (
management.autoRepair: true), but nodes are still
NotReady:
Step 4: Recover or release the reservation capacity [High Risk]
Guardrail: Don't modify GKE-managed instance groups or VMs directly
through Compute Engine. Manage node pools through GKE. Never delete healthy
node pools that run active jobs.
- If the user wants to repair
{leaking_nodepool_name} in place, enable node
auto-repair (doesn't free slots for {failing_nodepool_name}):
- If
{leaking_nodepool_name} is stale or the user wants to free its slots
for {failing_nodepool_name}, delete it through GKE: Link the user to
Delete a node pool
to delete {leaking_nodepool_name}, which frees the reserved slots its VMs
use.
- After the user deletes
{leaking_nodepool_name}, verify that enough
reservation slots are free: Follow
View reservations
to run gcloud compute reservations describe {reservation_name} --zone={zone} --project={reservation_project_id} and confirm that
specificReservation.inUseCount drops so the free slots
(specificReservation.count - specificReservation.inUseCount) are at least
the number of nodes that {failing_nodepool_name} needs before retrying
{failing_nodepool_name}.