Controlling Non-Production Kubernetes Costs with Gardener Shoot Hibernation
Use Gardener Shoot hibernation to stop idle dev and staging clusters, but verify status conditions and keep separate backups.
09 Jul 2026, 10:33 UTC

Idle non-production shoots are still billable
If you run Gardener Shoots for development, staging, or batch-processing namespaces, those clusters often sit idle overnight and on weekends. The Shoot control plane and worker nodes keep running, and you keep paying for them, even when no one is deploying or testing. The practical decision is to hibernate those Shoots outside of usage hours instead of leaving them powered on.
What Shoot hibernation actually does
In Gardener, a Shoot is a user cluster managed by the Gardener control plane running in a Seed cluster. Setting spec.hibernation.enabled: true tells Gardener to stop the Shoot control plane and scale worker nodes to zero. The Shoot object itself stays in the Garden API, and persistent etcd storage is generally retained, but the cluster is unavailable while hibernated.
This is not operating-system hibernation. It is a Kubernetes lifecycle action: the API server, scheduler, and controller manager stop, and worker nodes are removed from the cloud provider. Workloads cannot run until you wake the Shoot.
Where it fits and where it does not
- Good for: non-production, weekend-only, or batch workloads that tolerate temporary unavailability.
- Not for: production control planes that clients expect to reach continuously.
- Not a replacement for: backups or disaster recovery. Hibernation retains etcd storage in many cases, but it is not a tested restore path for seed or storage failure.
Worked example: hibernate and wake a Shoot
Run these commands from a machine with kubectl configured against the Garden cluster. You need read/write permission on the Shoot resource in the project namespace.
1. Inspect the current Shoot:
kubectl get shoot dev-workload -n garden-project-a -o yaml
Look for spec.hibernation and existing status.conditions.
2. Enable hibernation:
kubectl patch shoot dev-workload -n garden-project-a --type merge -p '{"spec":{"hibernation":{"enabled":true}}}'
Required permission: update on shoots in garden-project-a. Risk: any application or CI pipeline pointing at this Shoot will start failing immediately because the API server stops.
3. Verify the change took effect. Gardener reconciles spec.hibernation asynchronously, so do not assume the cluster is hibernated right after the patch:
kubectl get shoot dev-workload -n garden-project-a -o yaml | grep -A5 "status.conditions"
Expected check: a condition with type Hibernated and status True, plus control-plane and node conditions reflecting stopped or absent components. If you only see Progressing, wait and poll again.
4. Wake the Shoot when you need it:
kubectl patch shoot dev-workload -n garden-project-a --type merge -p '{"spec":{"hibernation":{"enabled":false}}}'
Poll status.conditions until the control plane reports healthy and worker nodes return. Then confirm a sample workload is reachable before telling users the cluster is back.
Trade-offs and limitations
Behavior varies by Gardener version, Seed version, cloud provider, and installed addons. Load balancers, persistent volumes, and addon pods may not come back exactly as they were. Wake-up lead time is not instantaneous, so communicate the window to anyone depending on the cluster.
Because hibernation is not backup, keep current, tested etcd snapshots and a separate restore procedure. Treat hibernation as a cost-control schedule, not a data-protection strategy.
Practical closing
Automate spec.hibernation.enabled through CI/CD or a Gardener-aware controller for dev and staging Shoots. Keep production Shoots unhibernated, document the expected wake-up lead time, and verify status conditions after every hibernate or wake cycle. Start with one non-production Shoot, confirm the condition transitions, then expand the schedule.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.