Deployments with fewer ready replicas than desired
What does ZopNight detect here?
A Deployment reporting fewer ready replicas than its spec requests is running at reduced capacity right now. ZopNight compares desired against ready. A gap of 1 on a 10-replica service is degraded; the same gap on a 1-replica service is a full outage nothing has alerted on.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1714 · RC-1814 · RC-1914 |
| Category | reliability |
| Severity | high |
| Metric | none — pure configuration read |
| Source | internal/rules/k8s/deployment_degraded.go |
Where it applies
Degraded is not the same as down, and both look the same here
The rule compares spec.replicas against status.readyReplicas. The gap is the finding.
What that gap means depends entirely on the denominator. Nine of ten ready is a service running at 90% capacity (probably fine, worth knowing). Zero of one ready is a complete outage, and it produces the identical shape of finding.
Read the ratio, not the difference.
Why a Deployment sits partially ready
Insufficient node capacity. Pods are Pending because no node satisfies their requests. Common after adding replicas without cluster autoscaling.
Readiness failing. Pods are Running but not passing their readiness probe: a dependency is unavailable, or the probe is stricter than the application.
Image pull failures. Wrong tag, missing pull secret, registry rate limit. The pod never starts.
Scheduling constraints unsatisfiable. Node affinity, taints, or a topology spread constraint that cannot be met with the nodes currently available.
The first two are by far the most frequent, and they need opposite responses. One is a capacity problem, the other an application one.
Persistent versus transient
Every rollout produces a temporary gap. That is the deployment strategy working, not a fault.
What matters is duration. A Deployment that has been short a replica for hours is stuck; one short for ninety seconds is mid-update. The rule cannot see how long the state has held, so a finding here is a prompt to check, not proof of a stuck workload.
From readyReplicas to the pod describe events
kubectl get deploy -A -o json | jq -r ' .items[] | select((.status.readyReplicas // 0) < .spec.replicas) | "\(.metadata.namespace)/\(.metadata.name)\t\(.status.readyReplicas // 0)/\(.spec.replicas)"'Then go straight to the pods, where the actual reason lives:
kubectl get pods -n <ns> -l app=<name>kubectl describe pod <pod> -n <ns> | tail -25The Events section at the bottom of describe names the cause in almost every case.