Kubernetes Resource Limits: A Practical Guide
Resource limits in Kubernetes are one of those things that seem optional until they are very much not. This post covers the practical patterns for setting CPU and memory limits on workloads running in production clusters.
Why Limits Matter
Without resource limits, a single misbehaving pod can consume all CPU time on a node, starving every other workload. Kubernetes calls this the "noisy neighbor" problem. Setting limits gives the scheduler the information it needs to enforce fair sharing.
Setting CPU and Memory Limits
Here is a deployment with both requests and limits set:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: my-app
image: my-app:latest
resources:
requests:
cpu: "250m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
The requests value is what Kubernetes uses for scheduling — it reserves that capacity on the node. The limits value is the ceiling. For CPU, exceeding the limit results in throttling; for memory, exceeding the limit results in the container being OOM-killed.
Checking Current Usage
Use kubectl top to see actual consumption before setting limits:
kubectl top pods -n my-namespace
kubectl top nodes
Match your limits to the 95th-percentile usage observed over several days, not the peak spike.
LimitRange for Namespace Defaults
Apply a LimitRange object to enforce defaults at the namespace level:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: my-namespace
spec:
limits:
- default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "64Mi"
type: Container
With this in place, any container that omits resources gets the namespace defaults automatically — no forgotten limits.
Summary
Set requests and limits on every workload, use kubectl top to calibrate them from observed usage, and enforce namespace defaults with LimitRange. Your cluster will thank you.