# HPA Allows Scale to Zero

> Flags HPAs with minReplicas 0, which only recover from zero with Object or External metrics and the HPAScaleToZero feature gate.

Source: https://zop.dev/integrations/kubernetes/recommendations/hpa-allows-scale-to-zero

---

## Zero is a floor the autoscaler may not climb back from

`minReplicas` defaults to 1. The
[HPA API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2/)
allows 0 only when the `HPAScaleToZero` feature gate is enabled and at least one Object or
External metric is configured. The
[horizontal pod autoscaling page](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
explains why: scaling to zero is not available for resource metrics such as CPU or memory
utilization, because those can only be measured on running pods. With no pods there is no CPU
reading, and nothing tells the controller to add the first replica.

The feature gate's status depends on the Kubernetes version. The API reference describes it as
alpha, while the current autoscaling page lists it as beta and enabled by default from v1.37, with
the gate needed on both the API server and the controller manager. On a managed EKS, GKE or AKS
control plane you do not set feature gates yourself, so what works is whatever your version
ships.

## Listing HPAs with a zero floor

```bash
kubectl get hpa -A -o json | jq -r '
  .items[]
  | select(.spec.minReplicas == 0)
  | "\(.metadata.namespace)/\(.metadata.name) metrics=\([.spec.metrics[]?.type] | join(","))"'
```

An HPA listing only `Resource` metrics is the risky case. One listing `External` or `Object`
metrics may be a deliberate scale-to-zero design.

## What ZopNight checks

The rule reads `minReplicas` from the HPA it collected and fires when it is exactly 0. It does
not read the metric types or the feature gate, so a correctly built scale-to-zero HPA is flagged
alongside a broken one. When `minReplicas` is not reported, the HPA is skipped. There is no
window; the finding clears once the minimum is 1 or more.

## Related settings reported elsewhere

The other HPA configuration checks cover different values of the same fields:
[HPA cannot scale](https://zop.dev/integrations/kubernetes/recommendations/hpa-cannot-scale) for a maximum of 1,
[HPA pinned](https://zop.dev/integrations/kubernetes/recommendations/hpa-pinned) for minimum equal to maximum,
and [HPA has no metrics](https://zop.dev/integrations/kubernetes/recommendations/hpa-has-no-metrics) for an
empty metric list. A Deployment scaled to zero by hand, rather than by an HPA, is reported by
[Stopped deployment](https://zop.dev/integrations/kubernetes/recommendations/stopped-deployment).

## Availability risk, not a saving

This medium-severity reliability finding has no savings figure. Scale-to-zero is attractive for
cost, but only when something reliable wakes the workload up again.

## Choosing a safe floor

1. Check the metric types in the HPA spec. If they are all `Resource` metrics, set
   `minReplicas` to 1 or more:
   `kubectl patch hpa <name> -p '{"spec":{"minReplicas":1}}'`.
2. If you want scale-to-zero, drive it from an External or Object metric that exists while the
   workload is idle, such as a queue length, and confirm your cluster version supports it.
3. While an HPA holds a workload at zero, the current docs describe a `ScaledToZero` condition on
   its status; check it with `kubectl describe hpa <name>` after the next idle period.
