Getting CPU and memory settings right in Kubernetes is less about memorizing one perfect ratio and more about matching resource requests and limits to the behavior of each workload. This guide is designed as a reusable reference for platform teams, SREs, and application engineers who need practical Kubernetes requests and limits best practices by workload type. It explains how requests affect scheduling, how limits affect runtime behavior, where teams commonly trigger throttling or OOMKilled events, and how to choose sane defaults for stateless APIs, background workers, batch jobs, data services, ingress components, and observability agents.
Overview
Resource management in Kubernetes sits at the intersection of performance, reliability, and cost. Set requests too low and the scheduler may pack too many pods onto a node, leading to noisy-neighbor contention or surprise evictions. Set requests too high and clusters become artificially full, driving waste and unnecessary scaling. Limits introduce another tradeoff: they can protect the node from runaway consumption, but badly chosen limits can also create avoidable CPU throttling or repeated memory kills.
For most teams, the hard part is not understanding the syntax. It is understanding the behavior. CPU and memory behave differently in Linux and in Kubernetes:
- CPU requests influence scheduling and relative access to CPU time under contention.
- CPU limits cap CPU usage and can cause throttling when a container wants to burst.
- Memory requests influence scheduling and help define how much memory the workload is assumed to need.
- Memory limits are hard ceilings. If a process exceeds them, the container can be terminated, often surfacing as
OOMKilled.
A useful mental model is simple: requests should represent what the workload reliably needs; limits should represent what the platform can safely allow. The gap between those numbers depends on whether the workload is bursty, latency-sensitive, memory-stable, batch-oriented, or inherently variable.
This is why a single cluster-wide rule rarely holds up. A Java API, a Go worker, an NGINX ingress controller, a Prometheus sidecar, and a nightly ETL job do not fail the same way. The rest of this hub maps sizing choices to those differences.
Core principles before tuning by workload type
- Measure first, then standardize. Start with observed usage from staging or production-like environments, then convert those observations into templates.
- Treat memory more conservatively than CPU. CPU contention often degrades performance; memory exhaustion often causes abrupt restarts.
- Avoid using limits as a substitute for profiling. Limits protect the cluster, but they do not explain leaks, spikes, or inefficient queries.
- Separate startup behavior from steady state. Some applications spike during cold start, cache warmup, or JIT compilation.
- Revisit after meaningful change. New releases, dependency updates, traffic shape changes, and cluster autoscaling policies can all invalidate earlier assumptions.
Topic map
Use this section as the quick-reference map for workload sizing. Each category below includes a practical strategy for CPU and memory requests and limits, plus the main failure mode to watch.
1. Stateless web APIs and microservices
These workloads usually have relatively stable memory usage and bursty CPU demand tied to request volume. For many teams, this is the most common place where aggressive CPU limits create avoidable latency.
Good starting approach:
- Set CPU requests near the baseline usage the service needs to stay responsive under normal load.
- Set CPU limits only if the cluster needs strict fairness controls; otherwise consider leaving CPU uncapped if your platform policy allows it.
- Set memory requests close to realistic steady-state usage.
- Set memory limits above typical peak memory, with room for traffic bursts, runtime overhead, and cache growth.
Watch for: CPU throttling, elevated tail latency, and rolling OOMs during traffic spikes or deployment warmups.
Practical rule: If a service is healthy at low traffic but slows badly during bursts without high node utilization, inspect CPU throttling before assuming the application is underprovisioned overall.
2. Background workers and queue consumers
Workers are often easier to scale horizontally than user-facing APIs, so resource strategy depends on whether throughput or latency matters more. Some workers are CPU-heavy; others are memory-heavy because they accumulate batches or hold large payloads in memory.
Good starting approach:
- Use CPU requests based on sustained throughput needs rather than brief spikes.
- Apply CPU limits if you need to stop a worker class from consuming all available compute on a node.
- Set memory requests and limits with extra care if jobs deserialize large messages, process files, or batch records.
Watch for: backlogs rising after deployments, workers restarting on large messages, or throughput collapsing when too many consumers are packed together.
Practical rule: For queue consumers, it is often better to lower concurrency inside the process than to rely only on tighter limits.
3. CronJobs and one-off batch jobs
Batch jobs are classic candidates for bad defaults because they run infrequently, have unusual peak behavior, and often inherit settings copied from services. Their real resource profile may only appear during end-of-month processing, data backfills, or large imports.
Good starting approach:
- Use CPU requests high enough that the job gets scheduled and finishes in a predictable window.
- Use CPU limits carefully. If faster completion matters more than strict fairness, overly low limits can turn short jobs into long-running ones.
- Set memory requests based on worst normal execution path, not average daily usage.
- Set memory limits with room for input-size variance, decompression, sort buffers, or temporary in-memory aggregation.
Watch for: jobs that succeed in test but fail in production-sized runs, missed scheduling windows, and node pressure during parallel batch activity.
4. JVM services
Java-based applications deserve their own category because heap sizing, off-heap memory, garbage collection behavior, and startup characteristics can make container memory use less intuitive. A pod can stay below heap settings and still exceed its memory limit because the runtime uses more than heap alone.
Good starting approach:
- Align JVM memory settings with container-aware behavior and leave room beyond heap for metaspace, direct buffers, threads, and native allocations.
- Keep memory limits comfortably above configured heap expectations.
- Be cautious with low CPU limits on latency-sensitive JVM services, especially if GC or warmup needs short bursts.
Watch for: OOMKilled despite apparently safe heap values, slow startup after scaling events, and inconsistent latency under CPU contention.
5. Data stores and stateful services inside Kubernetes
Running databases, caches, or brokers in Kubernetes requires more conservative sizing than stateless applications. These workloads are often less tolerant of memory pressure and restarts, and their operational profile depends heavily on storage, replication, and failure recovery behavior.
Good starting approach:
- Set requests close to expected real usage, especially for memory.
- Avoid casual overcommit on memory-heavy stateful workloads.
- Use memory limits carefully; too-tight caps can destabilize caches or trigger expensive recovery paths.
- Use CPU requests high enough to preserve predictable performance during contention.
Watch for: eviction sensitivity, replica lag, cache churn, and restart loops that take longer to recover than a stateless service would.
Practical rule: If a stateful service is important enough to run in-cluster, it is important enough to size explicitly rather than inherit namespace defaults.
6. Ingress controllers and edge components
Ingress controllers, gateways, and proxies often show bursty CPU usage with memory tied to connection count, configuration size, and buffering behavior. Because they sit on the request path, small resource mistakes can become broad service degradation.
Good starting approach:
- Set CPU requests to preserve responsiveness under ordinary traffic.
- Allow room for CPU bursts during spikes, reloads, or TLS-heavy traffic.
- Set memory requests and limits using connection and buffering patterns, not only idle usage.
Watch for: 5xx spikes under load, config reload slowness, and latency jumps that line up with CPU throttling.
For adjacent design choices, see Kubernetes Ingress Controller Comparison: NGINX vs Traefik vs HAProxy vs Cloud Native Options.
7. Observability agents, collectors, and sidecars
Telemetry components are easy to undersize because they are often treated as lightweight plumbing. In reality, logging and tracing pipelines can become CPU- and memory-intensive under incident conditions, traffic surges, or export backpressure.
Good starting approach:
- Set requests based on sustained telemetry volume, not quiet periods.
- Leave room for temporary spikes in queued data.
- Be especially careful with memory limits when buffers are enabled.
Watch for: dropped spans, collector restarts, rising queue depth, and loss of observability exactly when you need it most.
For deeper architecture tradeoffs, see OpenTelemetry Collectors Explained: Deployment Patterns, Tradeoffs, and Update Guide.
8. CI/CD runners and build workloads on Kubernetes
Build pods are often unusually spiky. Compilation, image builds, test execution, and dependency resolution can create short periods of high CPU, disk, and memory pressure. Copying production service defaults into runner pods usually fails.
Good starting approach:
- Size CPU requests for expected parallel work.
- Use CPU limits only after checking whether throttling is extending build time more than it saves contention.
- Set memory with enough headroom for language toolchains, test suites, and container build steps.
Watch for: flaky builds, random test crashes, and image builds failing only on shared runner nodes.
For pipeline troubleshooting more broadly, see CI/CD Pipeline Troubleshooting Checklist for Failing Builds and Deployments.
9. Low-latency or performance-sensitive workloads
Some services care more about consistent response time than about average resource efficiency. Trading systems, real-time pipelines, and specialized edge services may need more conservative requests and less restrictive CPU capping than ordinary web backends.
Good starting approach:
- Use stronger CPU requests to reduce noisy-neighbor effects.
- Be cautious with low CPU limits on critical request paths.
- Keep memory sizing conservative to avoid restart-driven latency events.
For examples of adjacent reliability concerns, see Low-Latency Market Data Pipelines in the Cloud: Networking and Observability for Trading Systems.
Related subtopics
Requests and limits do not exist in isolation. If you are building a durable sizing practice, keep these related areas in view.
Autoscaling and right-sizing loops
Horizontal Pod Autoscaler behavior depends on resource requests because utilization is typically measured relative to them. If requests are unrealistically low, autoscaling signals can become misleading. Vertical sizing reviews and horizontal scaling policy should be designed together, not separately.
LimitRange and ResourceQuota defaults
Namespace policies can improve consistency, but they can also spread bad defaults at scale. A LimitRange that forces low CPU limits everywhere may hurt latency-sensitive services. A default memory request copied across all teams may distort scheduling efficiency.
Pod Quality of Service classes
How requests and limits are set affects QoS behavior and eviction sensitivity. Teams do not need to optimize for labels alone, but they should understand the operational consequences of leaving values blank, matching them, or mixing them inconsistently across containers.
Node sizing and bin-packing strategy
Workload sizing and node shape are connected. Large requests on small nodes can strand capacity. Tiny requests on large nodes can hide contention until performance collapses. Cluster autoscaler behavior also changes the economics of over-requesting.
Runtime profiling and language-specific memory behavior
Go, Java, Node.js, Python, and native binaries do not consume memory the same way. If one team runs many services in the same language, language-aware templates are usually more effective than generic platform-wide presets.
Troubleshooting signals to keep handy
- OOMKilled events for hard memory failures
- CPU throttling metrics for over-restrictive CPU limits
- Restart counts to catch chronic instability
- Tail latency to see user-visible impact
- Queue depth or lag for worker underprovisioning
- Node memory pressure and evictions for cluster-level stress
Version changes can also shift assumptions around scheduling, defaults, or feature behavior. Keep an eye on your broader upgrade process with Kubernetes Version Skew Policy and Upgrade Planning Guide.
How to use this hub
The most effective way to use this guide is as an operating checklist rather than a one-time read.
- Classify each workload. Decide whether it is a stateless API, worker, batch job, data service, ingress component, or telemetry pipeline.
- Identify the dominant failure mode. Is the real risk throttling, OOMKilled restarts, long completion time, missed SLOs, or node contention?
- Collect baseline usage. Use representative traffic or job sizes, and separate startup behavior from steady-state behavior.
- Set requests first. Requests are the foundation for scheduling and autoscaling interpretation.
- Add limits deliberately. Do not assume every container needs a tightly capped CPU limit. Be stricter with memory only after understanding the application envelope.
- Test under stress. Validate settings during deployments, spikes, backfills, and failure scenarios, not just average traffic.
- Standardize by workload family. Turn what you learn into templates for APIs, workers, and batch jobs rather than forcing one universal default.
If you run a platform team, publish a short internal rubric such as: preferred default requests by runtime, when CPU limits are allowed, when memory limits are mandatory, and what metrics must be reviewed before promoting a service template. That kind of lightweight policy scales better than an undocumented set of tribal rules.
When to revisit
This topic should be revisited whenever the workload or the platform meaningfully changes. Resource settings are not permanent truths; they are operating assumptions that age.
Re-check requests and limits when:
- A service changes language runtime, framework version, or major dependency set.
- Traffic shape shifts, even if average volume does not.
- Batch input sizes grow or processing windows shrink.
- You enable new observability, sidecars, or security agents.
- Autoscaling policies or node instance types change.
- You adopt new ingress, collector, or platform patterns.
- Teams report OOMKilled events, throttling, backlog growth, or rising latency.
A practical review cadence:
- Review critical services after each major release.
- Review batch and worker classes after significant data-shape changes.
- Review platform defaults quarterly or after cluster policy updates.
- Review all sizing assumptions before large seasonal events or migration waves.
As this hub evolves, it can also connect to adjacent Kubernetes topics that influence sizing decisions, including registries, identity design for workloads, and specialized data pipelines. For example, if your deployment model adds more sidecars, image variants, or runtime identity controls, resource assumptions often need to be recalibrated alongside those changes. Relevant reading includes Container Registry Comparison: ECR vs GCR vs ACR vs Docker Hub and Workload Identity for AI Agents: Separating Who Runs from What They Can Do.
The practical takeaway is straightforward: use requests to describe what a workload truly needs, use limits to enforce safety where it matters, and tune both according to workload behavior instead of habit. If you do that consistently, you reduce wasted capacity, avoid more OOMKilled incidents, and make Kubernetes workload sizing a repeatable engineering discipline rather than a recurring guess.