Skip to main content

Scale GKE Node Pools to Zero Overnight with gcloud

Resize a GKE Standard node pool to zero in the evening and back in the morning, without the cluster autoscaler undoing it.

GKE has no stop button for a cluster. What you can do on a Standard cluster is shrink a node pool to zero nodes after hours, which deletes the node VMs and ends their Compute Engine charge, then grow it again before people arrive. This guide covers the two gcloud commands that matter, the autoscaler setting that silently reverses them, and what still bills while the pool is empty.

Autopilot clusters are out of scope: Google manages the nodes, and Autopilot workloads are priced on the compute resources their Pods request, so the lever there is scaling Deployments down, not resizing pools.

What you need first

  • A GKE Standard cluster with at least two node pools: one that stays up for system Pods, and one or more you want to empty.
  • gcloud authenticated as a principal holding container.clusters.update on the project (resize and autoscaling changes are cluster updates).
  • kubectl pointed at the cluster, to watch Pods move.

1. Record each pool before you touch it

Terminal window
gcloud container node-pools list --cluster dev-cluster --location europe-west1
gcloud container node-pools describe apps-pool \
--cluster dev-cluster --location europe-west1 \
--format="yaml(autoscaling)"
kubectl get nodes -l cloud.google.com/gke-nodepool=apps-pool

Write down the node count and, if autoscaling is on, its minNodeCount and maxNodeCount. You need these numbers to restore the pool in the morning. In a pool that spans several zones, sizes are per zone: --num-nodes=2 on a three-zone pool means six nodes.

2. Leave one pool running

The cluster autoscaler on Standard clusters never scales a whole cluster to zero, because one or more nodes must be available to run system Pods. Keep a small pool for those and only empty the pools that carry your application workloads.

3. Evening: turn off autoscaling, then resize to zero

If autoscaling stays on, the Pods you evict become Pending and the autoscaler adds nodes back to place them. Disable it on the pool first:

Terminal window
gcloud container clusters update dev-cluster \
--no-enable-autoscaling \
--node-pool apps-pool \
--location europe-west1
gcloud container clusters resize dev-cluster \
--node-pool apps-pool \
--num-nodes 0 \
--location europe-west1

The resize drains the nodes and gracefully terminates their Pods. Pods owned by a Deployment or StatefulSet go Pending until capacity returns. Bare Pods with no controller are not restarted, so move anything you care about under a controller first. Resize picks which nodes to remove at random.

4. Morning: resize back and restore autoscaling

Terminal window
gcloud container clusters resize dev-cluster \
--node-pool apps-pool \
--num-nodes 2 \
--location europe-west1
gcloud container clusters update dev-cluster \
--enable-autoscaling \
--node-pool apps-pool \
--min-nodes 1 --max-nodes 4 \
--location europe-west1

Use the numbers you recorded in step 1. --min-nodes and --max-nodes are also per zone; --total-min-nodes and --total-max-nodes set whole-pool limits instead and cannot be mixed with the per-zone flags.

Check that it worked

Terminal window
kubectl get nodes -l cloud.google.com/gke-nodepool=apps-pool
kubectl get pods -A --field-selector=status.phase=Pending

At night the first command returns no nodes and the Pending list shows the workloads waiting for the morning. After the morning run, nodes report Ready and the Pending list empties.

What keeps billing while the pool is empty

  • Cluster management fee. GKE charges a flat $0.10 per cluster per hour whatever the node count. The free tier gives each billing account $74.40 a month in credit, enough for one zonal Standard or Autopilot cluster; it does not cover regional clusters.
  • Persistent disks behind PersistentVolumes. A resize does not delete PVCs, and Persistent Disk is billed on provisioned space until you delete the disk.
  • The pool you kept for system Pods, plus any load balancers and reserved addresses the cluster owns.

Doing it with ZopNight

ZopNight discovers GKE clusters and node pools and can put a node pool on a schedule with start and stop cron expressions in an IANA timezone, the same schedules it uses for VMs. The account must be connected read + write for the schedule to execute; a read-only connection still shows the pools and their recommendations. The GKE node pool schedule page covers the resource-specific details, and namespace vs cluster scheduling explains when emptying a namespace beats emptying a pool.

Stop watching the waste.
Start cutting it.

See. Find. Fix. Automatic.

Connect your first cloud account in under 5 minutes. See your first remediation in under 7. No credit card required.

CDCR connect detect classify remediate
full audit every action traceable
read-only default access
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·