Deployments, StatefulSets and DaemonSets with containers missing CPU or memory requests
What does ZopNight detect here?
Kubernetes schedules pods by summing container requests against node capacity, so a container with no CPU or memory request is invisible to that math. ZopNight flags Deployments, StatefulSets and DaemonSets on EKS, GKE and AKS whenever any main container lacks either request, and lists every offender by name.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1700 · RC-1800 · RC-1900 · RC-1701 · RC-1801 · RC-1901 · RC-1702 · RC-1802 · RC-1902 |
| Category | reliability |
| Severity | high |
| Metric | none — pure configuration read |
| Threshold | any container without a CPU or memory request |
| Source | ZopNight |
| Permissions used | list deployments.apps · list statefulsets.apps · list daemonsets.apps |
Where it applies
Why an empty request breaks pod placement
A request is the amount of CPU and memory the kube-scheduler reserves for a container when it picks a node. The Kubernetes docs describe the scheduler comparing the sum of container requests with what each node can still offer. A container that declares nothing adds nothing to that sum, so the scheduler keeps placing pods on a node that is already busy in practice.
The failure shows up later, under load. CPU contention slows every pod on the node, and when
memory runs short the kernel starts killing processes. Eviction adds a second penalty:
pod QoS rules make a pod with no
CPU or memory requests or limits BestEffort, the first class evicted when a node comes under
pressure, and only pods using more than they requested are eviction candidates. With a request of
zero, any usage at all qualifies.
Scanning Deployments, StatefulSets and DaemonSets for missing requests
This lists each container, with its workload, that has no CPU request or no memory request. It
treats 0 as empty, the same value kubectl set resources uses to remove a request:
kubectl get deployments,statefulsets,daemonsets -A -o json | jq -r ' .items[] | .kind as $k | .metadata as $m | .spec.template.spec.containers[] | select(((.resources.requests.cpu // "0") == "0") or ((.resources.requests.memory // "0") == "0")) | "\($k) \($m.namespace)/\($m.name) \(.name)"'One missing request is enough to flag a workload
The same check runs for each workload kind (Deployments, StatefulSets and DaemonSets) on each managed cluster type: EKS, GKE and AKS. It reads the containers in the workload spec ZopNight collected from the cluster and fires when any container has an empty or zero CPU request, or an empty or zero memory request. Missing either one is enough. There is no metric, threshold or lookback window involved: it is a configuration read, repeated on every evaluation.
The finding names every offending container, not only the first, so a pod with a sidecar and an app container that both lack requests gets one recommendation listing both.
Containers and workloads the check ignores
Init containers are out of scope. They run to completion before the app containers start and often have no requests of their own by design, so scanning them would flag workloads that are already configured correctly. A workload with no containers listed in its spec produces nothing, and a workload where every container sets both requests is silent.
Be aware of the two admission-time cases in the false-positive note: a limit with no request is
copied into the request when the pod is created, and a namespace LimitRange can inject a
defaultRequest. The pods then have requests even though the template does not say so.
Risk rather than a dollar figure
This is a reliability rule and carries no savings estimate. The cost is operational: unpredictable packing, OOM kills during traffic peaks, and critical workloads evicted ahead of noisy ones.
Adding requests without guessing
- Run the Vertical Pod Autoscaler with
updateMode: "Off", which computes recommendations without touching pods, and read them withkubectl describe vpa. - Apply the values to the template, for example
kubectl set resources deployment api -c=app --requests=cpu=250m,memory=256Mi. - Roll out and watch for pods stuck in
Pending, which means the new requests exceed free node capacity. - Add a LimitRange with
defaultRequestto the namespace so new workloads start with a sensible floor.