Kubernetes resource requests and limits determine how workloads are scheduled, protected, and scaled. This practical guide shows how to size CPU and memory, verify live settings with kubectl, understand QoS classes and throttling, and run a repeatable review process without destabilizing the cluster.
Overview
In Kubernetes, a container's resource request is the amount of CPU or memory the scheduler uses when deciding where to place a Pod. A resource limit is the maximum amount the container is permitted to consume. These values are specified per container, while Pod-level capacity is effectively the sum of the containers in the Pod.
Requests influence placement and capacity planning. If a node does not have enough allocatable CPU or memory for a Pod's requests, the scheduler will not place it there, even if the node appears quiet at that moment. Limits influence runtime behavior: a container can be throttled when it reaches a CPU limit, while exceeding a memory limit can result in an out-of-memory termination.
A useful starting point is to treat requests as a reliable reservation and limits as a deliberate guardrail, not as arbitrary copies of one another. The correct values depend on workload behavior, availability requirements, node size, autoscaling policy, and the cost of unused capacity.
A simple sizing worksheet
For each container, record the following over a representative period that includes normal traffic and known busy periods:
| Input | What to record | Why it matters |
|---|---|---|
| CPU usage | Typical, high-percentile, and peak usage | Helps separate steady demand from short bursts |
| Memory working set | Typical and highest sustained usage | Memory pressure and leaks can cause termination |
| Startup behavior | Initialization CPU and memory | Short startup spikes can affect scheduling and probes |
| Replica count | Minimum and maximum replicas | Shows the cluster capacity required during scaling |
| Failure impact | Effect of throttling or termination | Sets the appropriate safety margin |
Use this worksheet as an engineering record rather than a one-time calculation. A release, traffic pattern, runtime version, or dependency change can alter the profile.
What to track
CPU requests and limits
CPU is measured in cores or millicores: 100m represents one tenth of a CPU core. CPU usage is compressible, so a container that reaches its CPU limit is generally throttled rather than killed. Sustained throttling can still increase latency, extend queue times, and cause health checks or request deadlines to fail.
Set the CPU request close to the workload's sustained requirement, with enough allowance for expected variation. Set a CPU limit only when a hard ceiling is useful for protecting neighbors or controlling burst behavior. A limit that is too low can create avoidable throttling; a very high limit can allow noisy-neighbor behavior unless other controls are in place.
Memory requests and limits
Memory is not compressible in the same way as CPU. When a container needs more memory than is available, the node may experience pressure and Kubernetes may terminate Pods according to eviction and prioritization behavior. If a container exceeds its memory limit, it can receive an out-of-memory termination.
Base memory requests on sustained working-set behavior, not on a brief idle reading. Include caches, language runtime overhead, connection pools, concurrency, and startup needs. A memory limit should leave room for expected growth while preserving a meaningful boundary. Setting it just above the current average often turns ordinary traffic growth into an incident.
QoS classes
Kubernetes assigns a Pod a Quality of Service class based on its container resource configuration:
- Guaranteed: every container has CPU and memory requests and limits, and each request equals its corresponding limit.
- Burstable: the Pod has at least one resource request or limit, but does not meet the requirements for Guaranteed.
- BestEffort: no container in the Pod specifies CPU or memory requests or limits.
QoS is one input into behavior during resource pressure; it is not a substitute for priorities, disruption policies, replicas, or application-level resilience. Review the resulting class intentionally. A critical service may need predictable reservations, while a batch workload may benefit from more flexible placement.
HPA interactions
The Horizontal Pod Autoscaler (HPA) commonly uses CPU or memory utilization relative to the configured request. For example, a target expressed as a percentage of CPU utilization has little meaning if the CPU request is far above or below the workload's real baseline. Raising a request can make the same absolute usage appear to be a lower percentage; lowering it can make utilization appear higher and may trigger more replicas.
Before changing requests, check the HPA target, current and desired replica counts, stabilization settings, and the metrics available to the autoscaler. Avoid treating a request change as an autoscaling fix without testing how it changes the signal.
Reference profiles
| Workload profile | Starting approach | Primary risk to watch |
|---|---|---|
| Stateless web API | Request sustained per-replica demand; allow measured CPU bursts | CPU throttling and latency during traffic peaks |
| Background worker | Request the normal processing baseline; cap concurrency deliberately | Queue growth, starvation, or excessive parallelism |
| JVM or managed-runtime service | Include heap plus runtime and native overhead | Container OOM before or around application heap limits |
| Cache or stateful service | Reserve memory for the working set and recovery behavior | Eviction, warm-up time, and data loss assumptions |
| Batch job | Use measured requirements and an appropriate priority | Cluster contention and unpredictable completion time |
These are profiles, not universal values. Measure the actual application before committing numbers.
Cadence and checkpoints
A monthly resource review is practical for actively changing services; a quarterly review may be sufficient for stable workloads. Review sooner after a major release, sustained traffic growth, a node-pool change, or an incident involving OOM kills, throttling, pending Pods, or evictions.
Verify configuration and placement
Start with the rendered workload rather than an un-applied source file:
kubectl get deployment <deployment> -n <namespace> -o yaml
kubectl describe pod <pod> -n <namespace>
kubectl get pods -n <namespace> -o wideInspect the container-level resources.requests and resources.limits, then compare them with the Pod's node, replica count, and recent scheduling events. To review node capacity and current usage, use:
kubectl describe node <node>
kubectl top pod -n <namespace> --containers
kubectl top nodekubectl top depends on a functioning metrics pipeline and is useful for a quick view, but it should not be the only source for sizing decisions. Compare it with longer-term dashboards and application metrics where available.
Run the review in a fixed order
- Confirm the workload's purpose, SLOs, traffic pattern, and replica policy.
- Compare requests with sustained usage and limits with observed peaks.
- Check for CPU throttling, memory working-set growth, OOM events, evictions, and pending Pods.
- Recalculate HPA behavior using the proposed requests.
- Test the change in a representative environment or a controlled rollout.
- Record the reason, expected effect, owner, and date for the next review.
For reliability context, pair this review with service objectives and error-budget discussions; resource changes should be evaluated against user-facing latency and availability, not utilization alone. The SLI and SLO guide provides a useful framework for that connection.
How to interpret changes
High CPU usage with throttling: determine whether the limit is unnecessarily restrictive or whether the application is exceeding its intended capacity. Check latency and throughput before simply raising the limit. If demand is sustained, scaling replicas or improving the hot path may be better than granting one container more CPU.
Memory usage rising over time: distinguish normal cache growth from a leak. A higher limit can delay an OOM event but does not correct unbounded growth. Check restart history, termination reasons, working-set trends, and runtime-level diagnostics.
Pods stuck Pending: compare aggregate requests with node allocatable capacity and placement constraints. A workload can be healthy at runtime yet unschedulable after a request increase. Review affinity rules, taints, topology constraints, and available node pools before reducing requests blindly.
HPA scaling unexpectedly: verify whether the request changed the utilization denominator, whether metrics are delayed, and whether each replica receives a similar workload. A request adjustment can change scaling behavior even when application traffic has not changed.
Frequent evictions: inspect node memory pressure, Pod priority, QoS class, and aggregate reservations. Raising every limit may increase contention; the safer response may involve capacity, workload isolation, replica distribution, or reducing memory demand.
When to revisit
Make resource management part of the platform team's operating rhythm rather than an emergency-only task. Revisit a workload at least monthly when it is growing or changing, and at least quarterly when its behavior is stable. Trigger an additional review after:
- a sustained change in request volume, job size, or concurrency;
- an application, runtime, dependency, or container-image upgrade;
- an OOM termination, eviction, repeated throttling, or scheduling failure;
- a change to HPA targets, replica limits, node pools, or instance types;
- a material change in availability, latency, or cloud capacity requirements.
At the next review, compare the last recorded request and limit values with current usage percentiles, restart and eviction events, HPA decisions, and node headroom. Keep a short change log explaining why each value moved. This makes future tuning safer and helps developers understand platform constraints through an internal developer platform or deployment workflow.
Finish with one controlled change at a time where possible: adjust the manifest, deploy gradually, watch resource and service indicators, and confirm that scheduling, autoscaling, and user-facing behavior remain healthy. Right-sizing is not about finding permanent numbers; it is a repeatable feedback loop that keeps Kubernetes workloads predictable as code, traffic, and infrastructure evolve.