There’s a particular kind of 3am incident that every Kubernetes operator dreads: a single misbehaving pod quietly consumes all available memory on a node, cascading into evictions, OOMKills, and a very unhappy on-call rotation. The frustrating part? In most cases, it was entirely preventable. Proper Kubernetes resource management — specifically, setting thoughtful requests and limits — is one of the highest-leverage things you can do for cluster stability.

Yet it’s also one of the most commonly skipped steps, especially when teams are moving fast. Developers push workloads without resource specs, platform engineers inherit under-defined clusters, and before long you’re dealing with noisy-neighbour problems that are genuinely hard to debug. This guide is here to change that.

Understanding requests vs limits — and why the distinction matters

Let’s get the fundamentals right. In Kubernetes, a resource request is what the scheduler uses to decide where to place a pod. It’s a guarantee: the node must have at least this much CPU and memory available before the pod lands there. A resource limit, on the other hand, is a ceiling — the maximum a container is allowed to consume.

These two numbers serve very different purposes, and conflating them causes real problems. Set your requests too low, and the scheduler will overcommit nodes beyond their actual capacity. Set your limits too low, and you’ll trigger unnecessary throttling or OOMKills on perfectly healthy workloads. The goal is to make both numbers reflect reality as closely as possible.

How Kubernetes QoS classes shape eviction behaviour

Here’s something that doesn’t get enough attention: the relationship between your resource configuration and Kubernetes QoS classes. Kubernetes assigns every pod one of three quality-of-service tiers, and this directly affects which pods get evicted first when a node comes under memory pressure.

  • Guaranteed: Requests and limits are set and equal for every container. These pods are evicted last.
  • Burstable: At least one container has a request or limit set, but they’re not equal. These pods are evicted based on usage relative to their requests.
  • BestEffort: No requests or limits are set at all. These pods are the first to go.

If you’re running critical services without resource specs, you’re inadvertently putting them in the BestEffort class — meaning Kubernetes will sacrifice them first in a resource crunch. That’s almost certainly not what you want for a production API or a data pipeline.

Key takeaway: Kubernetes doesn’t know which of your workloads are important unless you tell it. Resource requests and limits are how you communicate priority to the scheduler and the kubelet.

Practical guidelines for setting resource values

So how do you actually pick the right numbers? The honest answer is: start with observation, not guesswork. If you’re running on DIVERSITY’s managed Kubernetes environment, you have access to node-level metrics that make this much easier. Tools like Prometheus and Grafana (or the Kubernetes Metrics Server for a lightweight option) let you see actual CPU and memory consumption over time.

A reasonable starting approach for most workloads:

  • Set your memory request to the average observed usage under normal load, and your memory limit to roughly 1.5–2x that value to accommodate spikes.
  • For CPU requests, use the average consumption during typical operation. CPU limits are more nuanced — aggressive CPU limits cause throttling even when the node has spare capacity, so many teams set CPU requests but leave CPU limits unset for non-latency-sensitive workloads.
  • Revisit these numbers regularly. A service that handled 100 requests per second six months ago may look very different today.

One pattern worth adopting early is Vertical Pod Autoscaler (VPA) in recommendation mode. It won’t change anything automatically, but it will surface suggestions based on real usage — a useful sanity check against your manually configured values.

Namespace-level governance with LimitRanges and ResourceQuotas

Individual pod configuration is only half the story. For teams managing multi-tenant clusters or shared infrastructure — which is common in European enterprise environments where multiple business units share a platform — you also need cluster-level guardrails.

LimitRanges let you define default requests and limits for a namespace, so any pod deployed without explicit resource specs inherits sensible defaults. This is a simple but powerful way to prevent BestEffort pods from slipping through.

ResourceQuotas go a step further, capping the total CPU and memory that all workloads in a namespace can collectively consume. This is particularly valuable on bare metal Kubernetes clusters — like those available through DIVERSITY’s infrastructure — where overcommitment has direct consequences on physical hardware rather than being abstracted away by a cloud provider’s auto-scaling layer.

Avoiding the most common mistakes

A few anti-patterns come up again and again in production environments, and they’re worth naming explicitly.

Setting limits without requests is surprisingly common. If you only set a limit, Kubernetes uses that value as the request too, which can cause the scheduler to make poor placement decisions.

Using identical values for CPU requests and limits on all workloads pushes everything into the Guaranteed QoS class, which sounds good but actually prevents workloads from bursting when spare capacity exists. It’s often unnecessarily conservative.

Never revisiting resource specs is perhaps the most widespread issue. Applications change, traffic patterns shift, and resource profiles evolve. Treat your resource configuration as a living document, not a one-time task.

Resource governance as a sovereignty concern

There’s a broader point worth making here, particularly for organisations running on European cloud infrastructure. Operational predictability is a form of digital sovereignty. When you understand and control how your workloads consume resources, you’re less dependent on opaque autoscaling mechanisms and surprise billing — both of which can erode the cost transparency that running your own or managed infrastructure is supposed to deliver.

Teams running workloads on DIVERSITY’s bare metal or managed Kubernetes environments benefit from a level of infrastructure visibility that hyperscalers often obscure. But that visibility is only useful if you’re actually governing your workloads well. Resource limits and requests are where that governance starts.

Where to go from here

Getting Kubernetes requests and limits right isn’t a one-time fix — it’s an ongoing operational discipline. Start by auditing your existing namespaces for pods without resource specs. Add LimitRanges to enforce defaults. Instrument your clusters with metrics tooling so you can make evidence-based decisions rather than educated guesses.

The payoff is real: fewer OOMKills, more predictable scheduling, better cost attribution, and a cluster that behaves the way you expect it to under pressure. That’s not a small thing when you’re running production workloads that people depend on.

If you’re looking to build or migrate to a Kubernetes environment where you have genuine control over your infrastructure — without the lock-in or opacity of the major hyperscalers — it’s worth exploring what managed and bare metal Kubernetes looks like on European sovereign infrastructure.