Kubernetes resource requests and limits determine where workloads can run, how much capacity they reserve, and what happens under node pressure. This practical checklist explains how to size CPU and memory, validate assumptions with metrics, and avoid common causes of throttling, eviction, and OOMKilled containers.
Overview
A Kubernetes resource request is the amount of CPU or memory a container asks the scheduler to account for. The scheduler uses requests when deciding whether a Pod fits on a node. A limit is a maximum boundary enforced by the container runtime and Kubernetes resource controls. Requests affect placement; limits affect runtime behavior.
CPU and memory behave differently:
- CPU is compressible. When a container reaches its CPU limit, it can be throttled rather than terminated. Excessive CPU throttling may appear as increased latency, slower background work, or missed processing deadlines.
- Memory is not compressible. A container that exceeds its memory limit can be terminated and reported as
OOMKilled. During node pressure, Kubernetes may also evict Pods based on available capacity and Pod priority or quality-of-service factors.
Requests and limits should therefore be treated as a sizing decision, not as arbitrary values copied into every manifest. Start with observed workload behavior, account for normal and peak operation, and verify the result under realistic load. Resource sizing also interacts with autoscaling, node-pool capacity, Pod disruption planning, and deployment strategy.
For a broader incident workflow, pair this checklist with the Kubernetes CrashLoopBackOff troubleshooting runbook. A restart loop can have several causes, and resource exhaustion is only one of them.
Checklist by scenario
For a new application
- Separate containers by function. Estimate the application container, sidecars, agents, and initialization containers independently. A logging or proxy sidecar consumes resources too.
- Define requests for both CPU and memory. Without meaningful requests, scheduling and capacity planning become less predictable.
- Choose limits deliberately. A memory limit should protect the node from unbounded growth, but it must be high enough for legitimate peaks. Decide whether a CPU limit is needed after considering latency requirements and the cluster's resource policy.
- Test startup separately from steady state. Image loading, caches, migrations, and just-in-time compilation can create short-lived memory or CPU peaks that normal dashboards hide.
- Run a representative load test. Record resource usage at idle, typical traffic, expected peak traffic, and recovery after a spike.
For an established service
- Review a sufficiently long observation window that includes normal traffic and known busy periods.
- Compare actual usage with requests. If usage regularly exceeds the request, the Pod may be under-accounted for during scheduling. If usage is consistently far below the request, capacity may be stranded.
- Inspect CPU throttling, not just CPU utilization. A container can show moderate average usage while still experiencing short throttling periods that affect latency.
- Inspect memory working set, container restarts, termination reasons, and node memory pressure together. A single memory graph is not enough to identify whether the container limit or the node is the constraint.
- Change values gradually and observe the result through the next meaningful traffic cycle.
For a batch job or worker
- Size for the work unit that must complete within the required time, not only for the average worker.
- Check whether parallelism multiplies the request across many Pods. A modest request per Pod can still consume substantial node capacity at scale.
- Set a memory limit that accommodates the largest expected work item, or constrain work-item size explicitly.
- Use job retry behavior carefully. Repeated
OOMKilledattempts can increase load without making progress. - Confirm that temporary files, queues, and in-memory buffers are included in the estimate.
For a latency-sensitive API
- Measure tail latency during CPU contention, not just average response time.
- Investigate whether CPU limits create throttling at the point where traffic increases. If so, test a higher limit or a different policy rather than simply raising the request.
- Reserve enough memory for caches and concurrency, while keeping a safety margin below the container limit.
- Check that readiness probes do not send traffic before startup resource spikes have settled.
- Validate the rollout with the chosen deployment strategy. A rolling deployment can temporarily require capacity for old and new replicas; blue-green deployments can require substantially more parallel capacity. See the deployment strategy comparison when planning that change.
Example manifest
The following is a starting point, not a universal recommendation. The values should come from measurement and load testing:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
spec:
replicas: 3
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
containers:
- name: api
image: example/orders-api:stable
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
ports:
- containerPort: 8080
Remember that the effective Pod request and limit include the resources declared by all applicable containers. Review the complete Pod specification, not only the main application container.
What to double-check
| Symptom | Likely area to inspect | Useful checks |
|---|---|---|
OOMKilled or repeated memory restarts | Container limit, application growth, node pressure | Inspect termination reason, peak working set, restart history, and memory pressure events. |
| High latency with apparently available CPU | CPU throttling or short bursts | Compare throttled time with latency and inspect usage at a short interval. |
Pods stuck in Pending | Requests too large for available capacity | Run kubectl describe pod and inspect scheduler events, node allocatable capacity, taints, and affinity rules. |
| Pods evicted during node pressure | Node capacity, memory requests, QoS, and priorities | Inspect node conditions, eviction messages, Pod requests, and competing workloads. |
| New deployment does not fit during rollout | Temporary replica overlap | Calculate capacity for old replicas, new replicas, surge, and sidecars together. |
Useful baseline commands include:
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl top pod -n <namespace> --containers
kubectl describe node <node-name>
kubectl top depends on metrics being available and is best used with longer-lived dashboards for trend analysis. Use your observability stack to correlate resource usage with request rate, latency, error rate, restarts, and deployment events. Instrumentation and telemetry can make that correlation easier; the OpenTelemetry implementation guide covers a broader collection approach.
Common mistakes
- Copying one value to every workload. An API, queue consumer, database migration, and scheduled job have different resource profiles.
- Setting requests equal to limits without testing. This can simplify policy, but it may reserve more capacity than the workload normally needs and can make bursts harder to schedule.
- Removing limits to hide symptoms. This may postpone a container-level failure while increasing the risk that one workload consumes node capacity.
- Using averages to size memory. Memory failures often occur at the peak, during startup, or after a gradual leak. Review maximums and growth over time.
- Raising CPU limits when the real issue is concurrency. More CPU may not fix lock contention, inefficient queries, downstream latency, or an oversized worker pool.
- Ignoring non-application containers. Proxies, telemetry collectors, and security agents contribute to the Pod's total resource footprint.
- Changing values without checking autoscalers. Requests influence utilization-based autoscaling and can change scaling behavior even when application traffic is unchanged.
- Debugging only the Pod. Node allocatable resources, taints, affinity, quotas, limit ranges, and admission policies can all affect the final result.
When to revisit
Resource sizing is a living configuration. Revisit it before seasonal planning cycles, after a load-test result, and whenever workflows or tools change. A review is also appropriate after any of the following:
- a major application release, framework upgrade, or feature that changes concurrency or caching;
- a change to node types, node-pool size, autoscaling settings, or namespace quotas;
- an increase in
OOMKilledevents, CPU throttling, evictions, pending Pods, or unexplained latency; - a change in deployment strategy, replica count, sidecars, telemetry, or security agents;
- a new workload pattern, such as larger messages, heavier scheduled jobs, or a different traffic distribution.
Use this closing checklist during each review:
- Record current requests and limits for every container.
- Compare them with measured CPU and memory usage across normal and peak periods.
- Check throttling, restarts, evictions, pending scheduling events, and node pressure.
- Model rollout and autoscaling capacity, including sidecars and temporary replica overlap.
- Change one related group of workloads at a time, document the reason, and observe the outcome.
- Update the runbook with the new baseline and the symptoms that should trigger another review.
Good Kubernetes resource sizing is not about finding permanent numbers. It is about maintaining an evidence-based contract between workloads, schedulers, nodes, and operators as the system changes.