Deployments, StatefulSets and DaemonSets with containers missing a CPU or memory limit
What does ZopNight detect here?
ZopNight flags Deployments, StatefulSets and DaemonSets on EKS, GKE and AKS when any main container lacks a CPU limit or a memory limit, and names each container. Kubernetes documents that a container without a memory limit has no upper bound and can consume all available memory on the node, taking its neighbours down with it.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1703 · RC-1803 · RC-1903 · RC-1704 · RC-1804 · RC-1904 · RC-1705 · RC-1805 · RC-1905 |
| Category | reliability |
| Severity | medium |
| Metric | none — pure configuration read |
| Threshold | any container without a CPU or memory limit |
| Source | ZopNight |
| Permissions used | list deployments.apps · list statefulsets.apps · list daemonsets.apps |
Where it applies
What happens when a container has no ceiling
Requests decide where a pod is placed; limits decide how much it may use once it is there. The resource management documentation describes the two enforcement paths. A CPU limit is a hard limit the kernel enforces through throttling. A memory limit is enforced reactively with OOM kills when the kernel detects memory pressure. Without a memory limit, the same page says, the pod has no upper bound and can consume all available memory on the node.
That is the noisy-neighbour failure. One container with a leak grows until the node runs short,
and then the kernel and kubelet start killing and evicting processes, not necessarily the one
that caused it. The
memory assignment task
adds that a container with no limits has a greater chance of being killed in an OOM event. Limits
also decide quality of service: a pod is only Guaranteed when every container has CPU and memory
limits equal to its requests, per the
Pod QoS page.
Scanning workload templates for missing limits
The command below prints one line per container that lacks either limit, treating 0 as unset:
kubectl get deployments,statefulsets,daemonsets -A -o json | jq -r ' .items[] | .kind as $k | .metadata as $m | .spec.template.spec.containers[] | select(((.resources.limits.cpu // "0") == "0") or ((.resources.limits.memory // "0") == "0")) | "\($k) \($m.namespace)/\($m.name) \(.name)"'To see what a namespace injects by default, run kubectl get limitrange -n <namespace> -o yaml.
Either limit missing is enough
ZopNight reads the containers in each workload’s template and marks a container when its CPU limit or its memory limit is empty or zero. Both must be set for a container to pass. The finding lists every marked container, and one recommendation covers the whole workload. The same check runs for Deployments, StatefulSets and DaemonSets on each managed cluster type, with no metric or window: it is a configuration read on every evaluation.
Containers and cases it skips
Only main containers are checked; init containers run to completion before the app starts and are out of scope. Workloads with no containers listed produce nothing. The rule does not take a stance on the debate over CPU limits, so a team that omits them on purpose will see its containers listed. Missing requests, the scheduling side of the same fields, are covered by Missing CPU/memory requests.
Stability risk, with no dollar value
This medium-severity reliability finding carries no savings estimate. The cost shows up as OOM kills and evictions on shared nodes during peaks.
Setting limits from real usage
- Look at actual consumption with
kubectl top pod -n <namespace> --containers, over a busy period rather than a quiet one. - Set memory limits above the observed peak with margin, since exceeding them kills the
container:
kubectl set resources deployment api -c=app --limits=cpu=500m,memory=512Mi. - Decide deliberately on CPU limits; throttling can slow latency-sensitive services.
- Add a LimitRange
defaultto the namespace so new containers start with a ceiling.