Deployments set to 0 replicas that are more than a day old
What does ZopNight detect here?
ZopNight flags a Kubernetes Deployment on EKS, GKE or AKS whose `spec.replicas` is 0 once the Deployment is at least 24 hours old. A zero-replica Deployment runs no pods, but it keeps its Services, ConfigMaps, Secrets and PersistentVolumeClaims alive, and any disks behind those claims keep billing.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1732 · RC-1832 · RC-1932 |
| Category | orphan |
| Severity | low |
| Metric | spec.replicas |
| Threshold | equals 0, Deployment at least 24h old |
| Evaluation window | 24h |
| Source | ZopNight |
| Permissions used | list deployments.apps |
Where it applies
Zero pods, but not zero footprint
Scaling a Deployment to zero, for example with
kubectl scale deployment/<name> --replicas=0 from the
Deployments documentation,
stops its pods and frees their node capacity. Everything around the Deployment stays: the Service
pointing at it, its ConfigMaps and Secrets, and any PersistentVolumeClaims it used. Claims backed
by cloud disks keep billing for their provisioned size, and a LoadBalancer Service keeps its
cloud load balancer.
The other cost is confusion. A Deployment at zero looks like something that could come back at any moment, so nobody deletes its dependencies, and after a few months nobody remembers why it was parked. If an HPA targets it, Kubernetes treats a target set to zero as an implicit maintenance-mode deactivation: the HPA stops adjusting it until someone changes the replica count or the HPA’s minimum.
Listing Deployments set to zero
kubectl get deployments -A -o json | jq -r ' .items[] | select(.spec.replicas == 0) | "\(.metadata.namespace)/\(.metadata.name) created=\(.metadata.creationTimestamp)"'To see what each one still holds on to, list the claims and Services in the same namespace:
kubectl get pvc,services -n <namespace>Gate: zero replicas and a day of age
ZopNight reads the replica count from the Deployment spec and fires when it is exactly 0. A Deployment created a few minutes ago, or one briefly at zero during a rollback, would otherwise flicker in and out of the results, so the rule also requires the Deployment to be at least 24 hours old by its creation timestamp. Note that this is the object’s age, not how long it has been at zero. When the replica count or creation time is missing, no finding is raised.
What it does not measure
The rule does not look up the claims, Services or other objects around the Deployment, so it cannot tell you how much they cost. It also does not read intent: a Deployment scaled to zero by a schedule or kept as a warm standby looks the same as an abandoned one. StatefulSets are out of scope. Services that end up with no pods behind them are reported separately by Service with no endpoints.
A cleanup item with no computed saving
The Deployment object itself has no charge, so the finding carries no dollar figure and is filed as an orphan. Any saving comes from the resources you remove along with it.
Deciding between delete and document
- Ask the owning team whether the Deployment will ever run again.
- If not, delete it with
kubectl delete deployment <name>. - Remove the claims, Services, ConfigMaps and Secrets that only it used.
- If it is parked on purpose, add an annotation recording the reason and an owner.