Node Resource Overcommitment in Kubernetes

Node Resource Overcommitment in Kubernetes

How Kubernetes promises more CPU and memory than a machine physically owns, why that is both a clever money-saver and a risk, and how to control it with requests, limits, quality-of-service classes and eviction.

Airlines sell more tickets than there are seats on a plane. They do this because they know, from years of data, that a few passengers never show up. Most days the bet works, the plane is full, and the airline earns money from every seat. On a rare day, everyone shows up, and the airline must send some people home unhappy. Kubernetes nodes can behave in exactly the same way. A node can hand out promises for more CPU and memory than the machine really has, betting that not every application will use its full share at the same moment. That bet is called overcommitment.

This guide explains overcommitment from the ground up. You do not need to know Linux internals or Kubernetes scheduling before you begin. Every new word is explained when it first appears, and every big idea comes with an everyday comparison. By the end, you will understand how Kubernetes counts resources, what happens when the bet goes wrong, how to measure how much you are overcommitted, and how to choose a level that saves money without waking people up at night.

1What Overcommitment Really Means

Overcommitment means the total amount of resources promised to the pods on a node is larger than the amount the node can actually deliver.

A node is one machine in a Kubernetes cluster. It might be a physical server or a virtual machine in the cloud. Every node has a fixed amount of processing power, which we call CPU, and a fixed amount of memory, which we call RAM. Pods are the small packages that run your applications, and each pod asks for some of that CPU and memory. When the sum of what pods are allowed to use is higher than what the node owns, the node is overcommitted.

This sounds dangerous, and sometimes it is. But it is also normal and, in most companies, intentional. Applications rarely use all the resources they could. A web service might be sized for the busiest hour of the year but spend most days using a small part of its allowance. If every pod reserved its worst case, nodes would sit mostly idle and the bill would be huge.

Simple Analogy

Think of a shared office with fifty desks and eighty employees who each work from the office two or three days a week. The company gave every employee permission to use a desk, so on paper there are eighty promises for fifty desks. Most days it works perfectly. On a rare day when seventy people come in, some must stand or work in the cafeteria. Overcommitment is the same kind of planned sharing.

Term 1

Capacity

The total CPU and memory that a machine physically has.

Term 2

Request

The amount a pod asks Kubernetes to set aside for it when deciding where it should run.

Term 3

Limit

The most a container is allowed to use, even if more is free on the machine.

Term 4

Overcommit

Promising, through limits, more than the node can give if everyone asks at once.

i
Key Idea

Overcommitment is not a bug or a misconfiguration by itself. It is a trade-off between money saved and risk accepted, and the skill is choosing the right amount of it for each kind of workload.

2Requests and Limits: The Two Numbers That Matter

Every container can carry two numbers for each resource, and they do very different jobs.

When you describe a container, you can state a request and a limit for CPU and for memory. These two numbers are often confused, and the confusion causes most overcommitment problems. The request is a promise Kubernetes makes to the container about scheduling. The limit is a ceiling that the node enforces while the container is running. The first is about getting a seat. The second is about how much you may eat once you are seated.

NumberWho Uses ItWhen It MattersWhat It Controls
RequestThe scheduler, and the node under pressureWhen choosing a node, and when resources are scarceWhere a pod can be placed and how it is ranked for protection
LimitThe node’s kernelWhile the container runsThe maximum it may use before being slowed or stopped
Simple Analogy

At a restaurant buffet, the request is the table you reserved, which decides whether there is a place for you. The limit is the rule that says you may take at most three plates. The reservation does not stop you from eating less, and the plate limit does not guarantee food will be available if the buffet runs out.

The gap between request and limit

The distance between the request and the limit is called the burst room. A container that requests half a CPU and has a limit of two CPUs may use up to two CPUs when the node has spare capacity. When many containers use their burst room at the same moment, the node can run out, and that is when overcommitment turns from a saving into a problem.

Request
What the scheduler counts
Limit
What the kernel enforces
Usage
What the container actually consumes
!
Common Misconception

Many people think a limit reserves resources. It does not. A limit only caps usage. Only the request is used to decide how much space a pod takes on a node when the scheduler places it.

3How the Scheduler Counts Resources

The scheduler is the part of Kubernetes that picks a node for each new pod, and it does arithmetic using requests only.

When a pod is created, the scheduler looks at every node and asks a simple question: after adding the requests of the pods already on the node, is there still enough room for this new pod’s requests? Room is measured against a number called allocatable, which we will explain in the next chapter. If the answer is yes, the node is a candidate. The scheduler then picks the best candidate using extra scoring rules.

Notice what the scheduler does not look at. It does not look at the limits when deciding whether a pod fits. It does not look at how much CPU or memory the existing pods are actually using right now. It only adds up the numbers people wrote down as requests. This is why requests are the most important numbers in a cluster, and why wrong requests cause so many surprises.

flowchart LR
  A["New pod with requests and limits"] --> B["Scheduler reads requests only"]
  B --> C["Sum requests of pods on each node"]
  C --> D{"Fits within allocatable?"}
  D -- "Yes" --> E["Node is a candidate"]
  D -- "No" --> F["Node is skipped"]
  E --> G["Best scoring node is chosen"]
        
FIG 1 — The scheduler fits pods using requests, never limits or live usage
Simple Analogy

A hotel booking system assigns rooms using the reservations written in its book. It does not walk through the corridors to see which guests are actually inside. If guests reserved big suites and use only a bed, the system still believes the suites are full, and new guests are turned away even though much of the hotel looks empty.

Two ways to get it wrong

If requests are too high

  • Nodes look full while real usage is low
  • The cluster scales up and the bill grows
  • Capacity is wasted, but pods are safe

If requests are too low

  • Too many pods are packed onto one node
  • Real usage can exceed the machine’s capacity
  • Slowdowns, evictions and restarts appear
i
Remember

The sum of requests on a node can never exceed what is allocatable. The sum of limits can, and that is exactly where overcommitment lives.

4Node Capacity, Allocatable and Reserved Space

Not all of a machine belongs to your pods. Some of it is kept back for the system itself.

Imagine a machine with sixteen units of memory. You might assume your pods can use all sixteen. In reality, the operating system needs memory to run. The Kubernetes helper program on each node, called the kubelet, needs memory. The container runtime, which actually starts containers, needs memory too. If your pods used every last unit, these essential programs would starve, and the whole node could become unresponsive.

Kubernetes handles this by subtracting reserved space from the total. The result is called allocatable, and it is the number the scheduler uses. Three kinds of reservation are commonly subtracted. One is set aside for Kubernetes system programs. One is set aside for the operating system’s own programs. The third is a safety margin called the eviction threshold, which is the amount of free memory the kubelet tries to keep so it has time to react before the machine runs dry.

flowchart TD
  A["Node capacity: total physical resources"] --> B["Minus kube-reserved for Kubernetes programs"]
  B --> C["Minus system-reserved for operating system"]
  C --> D["Minus eviction threshold safety margin"]
  D --> E["Allocatable: the space pods may be promised"]
        
FIG 2 — From raw capacity to allocatable resources
Simple Analogy

A restaurant with fifty tables does not seat fifty parties. A few tables are kept for staff meals, a few are kept clear for the kitchen’s pass, and a few are left open in case of emergencies. The seating chart given to the host shows only the tables actually available for guests. Allocatable is that seating chart.

Why small nodes lose more

The reserved amounts are not a fixed percentage. Some of the reservation is a flat amount that every node pays no matter how big it is. That means small nodes lose a larger share to overhead than big nodes. A tiny machine might lose a quarter of its memory, while a large machine might lose only a few percent. This is one reason node size matters when you plan how much overcommitment you can safely allow.

!
Common Mistake

Teams that set no reservations at all give pods the whole machine on paper. When pods use real memory up to the edge, the operating system or the kubelet can be starved, and the node stops responding even though no pod broke a limit. Always reserve space for the system.

5CPU: The Resource That Can Be Squeezed

CPU is called compressible, which means that when there is not enough, programs slow down but do not die.

CPU time is like a road shared by many cars. When there are more cars than lanes, everyone moves slower, but nobody is destroyed. This is why experts call CPU a compressible resource. If a node runs short of CPU, pods simply get less processing time each, and requests take longer to answer. That is annoying, but usually recoverable.

Kubernetes uses two different mechanisms for CPU, one for the request and one for the limit. The request is turned into a weight. When several containers want CPU at the same time, the kernel shares the processing time in proportion to those weights. A container with a request twice as large as its neighbor’s gets about twice the share when the machine is busy. When the machine is not busy, containers can use more than their request freely.

Simple Analogy

Picture a pizza being shared at a party. If only two people are hungry, each can eat as much as they like. If ten people arrive at once, everyone gets a slice in proportion to a fair share agreed earlier. The request is that agreed fair share. It only matters when the pizza is scarce.

The CPU limit works differently

The limit is not a weight. It is a hard cap enforced by dividing time into small windows, commonly one tenth of a second. In each window, the container receives a quota of CPU time. Once the container has used its quota, it is paused until the next window begins, even if the machine is completely idle. This pausing is called throttling. A throttled container does not crash, but it stops working for part of each window, and the pauses can add noticeable delay to every request it handles.

Mechanism 1

CPU request

Becomes a relative weight. Matters only when the node is busy and containers compete.

Mechanism 2

CPU limit

Becomes a time quota per window. Enforced even when the machine has idle CPU, causing throttling.

!
Hidden Cost

A container can be throttled while the node shows plenty of idle CPU. If your application feels slow but the node looks quiet, throttling caused by a tight CPU limit is a prime suspect.

Example: The slow checkout service

A shop’s checkout service has a CPU request of one core and a limit of one core. During a short burst of traffic, it needs two cores for a few moments but is capped, so it pauses repeatedly. Customers see slow pages even though the node is mostly idle. Raising or removing the limit fixes the delay.

6Memory: The Resource That Cannot Be Squeezed

Memory is incompressible. When it runs out, something must be killed.

Memory behaves very differently from CPU. A program that holds data in memory cannot work with less memory the way it can work with less CPU time. You cannot shrink a loaded photo or an open database table and expect the program to carry on. When the machine truly runs out of memory, the operating system has only one option: it must stop some program to free memory. This is why experts call memory an incompressible resource, and why memory overcommitment is far more dangerous than CPU overcommitment.

When a container tries to use more memory than its limit, the kernel stops it immediately. This event is called an out-of-memory kill, usually written as OOM kill. Kubernetes then notices the container died and restarts it according to the pod’s rules, and the pod’s status often shows the reason as out of memory. If the application keeps using too much memory, it will be killed again and again, and the pod will seem to be stuck in a restart loop.

Simple Analogy

A glass of water cannot hold more than its size. If you keep pouring, the water overflows no matter how politely you ask. CPU is more like a queue at a shop, where people just wait longer. Memory is the glass: when it is full, the next drop spills.

Two kinds of memory kill

1

Container-level kill

The container goes above its own memory limit. Only that container is stopped. Other pods on the node are not affected.

2

Node-level pressure

The whole node runs low on memory because too many pods are using real memory at the same time. The kubelet or the kernel must choose victims, even if no single pod broke its own limit.

The second case is the real danger of memory overcommitment. A node can have thirty pods, each safely under its own limit, and still run out of memory because the sum of their real usage exceeds the machine’s total. That is exactly the full-flight situation of our airline analogy.

i
Practical Rule

Treat CPU overcommitment as a performance risk and memory overcommitment as a stability risk. Be generous with the first for non-critical workloads and careful with the second for everything.

7Quality of Service Classes

Kubernetes sorts every pod into one of three classes, and the class decides who is protected when things go wrong.

You never choose a quality-of-service class directly. Kubernetes assigns it automatically based on how you wrote the requests and limits. The class is then used by the node to decide which pods are most important to keep alive and which are the first to lose their place. Understanding the three classes is the key to predicting what will happen during a crunch.

Class 1

Guaranteed

Every container in the pod has a CPU and memory request and limit, and the request equals the limit for each. These pods are the most protected and are never overcommitted individually.

Class 2

Burstable

At least one container has a request or limit, but the pod does not meet the Guaranteed rule. These pods can use more than they asked for and are protected in proportion to their request.

Class 3

BestEffort

No container has any request or limit at all. These pods get whatever is left over and are the first to be sacrificed.

Simple Analogy

On a crowded lifeboat, guests with a numbered seat ticket are the Guaranteed class: their seat is theirs. Guests with a ticket that says “a seat or standing room” are Burstable: they can stretch into free space but may be asked to give some back. People without tickets are BestEffort: they come aboard only if there is room and are the first to leave if the boat gets heavy.

ClassHow You Get ItOvercommit ExposureWhen Resources Are Scarce
GuaranteedRequests equal limits for CPU and memory in every containerNone for the pod itselfLast to be stopped
BurstableSome requests or limits, but not equal everywhereBetween request and limitStopped in order of how far above request they are
BestEffortNo requests or limitsUnboundedFirst to be stopped
!
Common Mistake

Leaving requests and limits empty for many pods creates a node full of BestEffort pods. They look free but they are the first victims and they invisibly consume resources that other pods thought they had reserved.

i
Design Hint

Use Guaranteed for databases and critical services, Burstable for ordinary applications, and BestEffort only for work you do not mind losing, such as experiments.

8Node Pressure and Kubelet Eviction

When a node starts to run out of something, the kubelet steps in and removes pods on purpose to protect the machine.

The kubelet, the Kubernetes helper program on each node, constantly watches key signals such as how much memory is free, how much disk space is free, and how many process slots are left. You can set thresholds for these signals. When a signal crosses a threshold, the kubelet marks the node as under pressure and begins to evict pods, which means it stops them and asks the cluster to run them somewhere else.

flowchart TD
  A["Kubelet watches signals"] --> B{"Threshold crossed?"}
  B -- "No" --> A
  B -- "Soft threshold" --> C["Wait for grace period"]
  B -- "Hard threshold" --> D["Act immediately"]
  C --> E["Mark node under pressure"]
  D --> E
  E --> F["Stop new pods from scheduling here"]
  F --> G["Rank pods and evict until signal recovers"]
        
FIG 3 — From a crossed threshold to eviction

Soft and hard thresholds

A soft threshold gives pods a grace period. The kubelet waits to see whether the pressure goes away on its own, and if it does not, it begins a gentle shutdown that gives pods time to finish. A hard threshold has no waiting. The kubelet acts at once, because the machine is close to trouble. Most clusters have a default hard threshold for free memory, and teams that run overcommitted nodes usually tune these numbers carefully.

Who is evicted first?

When the kubelet must pick victims, it follows a clear order. Pods using more than they requested are considered before those within their request. Among those, lower priority pods go first. Among pods of equal priority, the ones using the most beyond their request go first. This is the practical meaning of the quality-of-service classes: BestEffort pods have no request, so any usage exceeds it, and they are first in line.

1

Pods using more than their request

They took more than they promised to need, so they are the first candidates.

2

Lower priority first

Among those candidates, pods with a lower priority value are removed earlier.

3

Largest overuse first

Among equals, the pod using the most beyond its request is removed first.

Simple Analogy

When a theater must clear seats for a fire drill, staff first ask people who took extra seats with their coats and bags to move, then work through the least important guests, and leave the guests who stayed neatly in their own seat for last. Eviction follows that same fairness rule.

!
Eviction Is Not a Crash

An evicted pod is deliberately stopped by the kubelet and is usually recreated elsewhere by its controller. It still means users may see errors for a moment, so frequent evictions are a sign that nodes are packed too tightly.

9OOM Kills Versus Evictions

Two different systems can stop your pods for lack of memory, and they behave very differently.

People often use the words eviction and OOM kill as if they meant the same thing. They do not. An eviction is a polite, planned action by the kubelet. An OOM kill is a sudden action by the operating system kernel. Knowing which one happened tells you where to look for the cause.

QuestionKubelet EvictionKernel OOM Kill
Who acts?The kubeletThe Linux kernel
How fast?Usually gradual, may give a grace periodInstant
What is removed?Whole podOne container process
What triggers it?A node signal crossing a thresholdA container passing its memory limit, or the node truly running out
What do you see?Pod shows an evicted status with a messageContainer shows a terminated reason of out of memory
Can you prevent it?Yes, by tuning thresholds and requestsOnly by right sizing limits and usage
Simple Analogy

An eviction is the building manager politely knocking on doors and asking tenants to leave because the building is too crowded. An OOM kill is the circuit breaker slamming off because too much power was drawn. One is organized and reasoned. The other is sudden and automatic.

The kernel’s scoring list

Linux keeps a score for each process that says how willing the system is to kill it when memory runs out. Kubernetes sets these scores according to quality-of-service class. Guaranteed pods receive a very protective score. BestEffort pods receive the highest score, so they are chosen first. Burstable pods receive a score that depends on how large their memory request is compared to the node, so pods with larger requests are somewhat safer. This is the second layer of protection after kubelet eviction and it matters when memory runs out faster than the kubelet can react.

i
Why Both Exist

The kubelet checks signals at intervals, so a sudden memory spike can outrun it. The kernel acts instantly as a last line of defense. Healthy clusters rarely need the kernel to step in at node level, because the kubelet acted earlier.

10Disk, Process Slots and Other Resources

CPU and memory get the attention, but nodes can run out of other things too.

A node has other limited resources that pods can exhaust. Pods use temporary disk space for logs, caches and scratch files, called ephemeral storage. Pods also create processes, and each node can only keep track of so many. If a single pod uses too many of these, the whole node suffers, and the kubelet reports it as disk pressure or process-slot pressure.

Resource 1

Ephemeral storage

Temporary disk used by a pod’s writable layer, logs and scratch folders. Can have requests and limits like CPU and memory.

Resource 2

Process slots

Each node can only run a limited number of processes. A runaway program creating thousands can starve neighbors.

Resource 3

Image storage

Downloaded container images take space, and a node with many different images can fill its image disk.

Resource 4

Network and device limits

Network bandwidth, special hardware and open file counts are other shared resources that can become bottlenecks.

Simple Analogy

A shared kitchen has limited stove burners, fridge space and counter room. If one cook fills the whole fridge with leftovers, nobody else can store anything, even though the stoves are free. Every shared resource needs its own fair rules, not just the glamorous ones.

Example: The chatty logger

An application writes huge debug logs to its own folder. Over several hours, it fills the node’s disk. The kubelet detects disk pressure and begins evicting pods that have nothing to do with the problem. A limit on ephemeral storage would have stopped the chatty pod first.

!
Common Mistake

Teams carefully tune CPU and memory and forget storage. Disk pressure evicts pods just as readily as memory pressure does, and it is often harder to diagnose because dashboards focus on CPU and memory.

11Why Teams Overcommit on Purpose

If overcommitment is risky, why does almost every large cluster do it? Because the alternative is expensive waste.

Studies and field reports from many organizations repeatedly show that most Kubernetes clusters use a small fraction of the CPU and memory that is requested for them. Teams ask for generous amounts to feel safe, and then the applications use far less on a typical day. If the cluster honored every request as a true reservation of real usage, most of the money spent on machines would buy idle capacity.

Simple Analogy

A city does not build a road wide enough for every resident to drive at the same moment. It builds a road for the usual rush hour and accepts that on the rare day of a big event there will be a traffic jam. Building for the worst possible day would cost far more than the jam ever costs.

Benefits of a planned overcommit

Advantages

  • Higher utilization means fewer nodes and a lower bill
  • Bursty applications can use idle capacity during spikes
  • Different workloads peak at different times, so sharing smooths demand
  • Teams are not forced to size every pod for its worst second
  • Faster scheduling because more pods fit

Disadvantages / Trade-offs

  • Noisy neighbors can slow each other down
  • Memory pressure can cause evictions and restarts
  • Performance becomes harder to predict
  • Capacity planning must rely on real usage, not only on paper numbers
  • Incidents are harder to diagnose because many pods share a machine

Statistical multiplexing in plain words

The idea behind safe overcommitment has a fancy name, statistical multiplexing. It simply means that when many independent workloads share a resource, their peaks rarely line up. One service is busy in the morning, another at night, a batch job runs at midnight. Added together, the total demand is smoother and lower than the sum of every individual peak. The more independent the workloads, the safer the bet.

i
Watch for Correlated Peaks

The bet fails when peaks line up, for example when a big sale makes every shopping service busy together, or when a failure makes every pod restart at once. Correlated demand is the enemy of overcommitment.

12Measuring How Overcommitted You Are

You cannot manage a risk you have not measured. A few simple ratios tell you exactly where you stand.

To measure overcommitment, you compare three totals for each node or for the whole cluster: the sum of requests, the sum of limits, and the real usage. All three are compared against allocatable. Each ratio answers a different question and together they give a complete picture.

Ratio 1

Requests to allocatable

How full the node looks to the scheduler. Cannot exceed one hundred percent. Shows how much room is left for new pods.

Ratio 2

Limits to allocatable

The overcommit ratio. Above one hundred percent means the node has promised more burst room than it owns.

Ratio 3

Usage to allocatable

How busy the node really is. This is the number that predicts pressure and evictions.

Ratio 4

Usage to requests

How accurate your requests are. Very low means waste. Above one hundred percent means pods are leaning on burst room.

flowchart LR
  A["Sum of limits: promised burst room"] --> D["Allocatable: what the node can really give"]
  B["Sum of requests: what the scheduler counted"] --> D
  C["Real usage: what pods consume now"] --> D
  D --> E["Compare the three to judge risk"]
        
FIG 4 — Three totals measured against allocatable
Simple Analogy

A bank has three numbers worth watching: the total of all credit cards it has issued, the total that customers have actually borrowed, and the cash it holds. The bank survives as long as actual borrowing stays well within cash, even though the total credit limits are far larger. Limits are credit cards, usage is borrowing, and allocatable is cash.

Reading the results

What You SeeWhat It Usually MeansTypical Action
Requests high, usage lowRequests are paddedRight size requests downward
Requests low, usage highPods are squeezing onto nodes and burstingRaise requests to match reality
Limits far above allocatable, usage lowSafe overcommit for nowWatch peaks, keep a safety margin
Usage close to allocatablePressure is nearAdd capacity or lower density
i
Look at Peaks, Not Averages

Averages hide danger. A node that averages forty percent memory usage but spikes to ninety-five percent for a minute every hour is a node that will produce evictions. Measure high percentiles over a long enough window.

13Noisy Neighbors and Cascading Failures

The worst overcommitment stories are rarely about one pod. They are about one pod hurting many others.

A noisy neighbor is a pod that uses so much of a shared resource that other pods on the same node suffer. With CPU, neighbors see slower response times. With memory, neighbors may be evicted. With disk and network, everyone’s input and output slows. Since the pods are different applications owned by different teams, nobody sees the connection until someone digs deep.

Simple Analogy

In an apartment building with thin walls, one resident’s loud party keeps everyone awake. The loud resident did nothing wrong by their own rules, and the building rules simply did not limit noise. Resource limits are the noise rules of a shared node.

The cascading failure

The most dangerous pattern is the cascade. A node comes under memory pressure and evicts several pods. Their controllers recreate them on other nodes. Those nodes now receive extra load and may also reach their thresholds. They evict pods, which move again, and the problem spreads across the cluster like a falling row of dominoes. Meanwhile, applications that restart need extra CPU and memory to start up, which adds further pressure.

flowchart TD
  A["Node A under memory pressure"] --> B["Pods evicted from Node A"]
  B --> C["Pods rescheduled onto Node B and C"]
  C --> D["Startup spikes add load to B and C"]
  D --> E["Node B reaches pressure"]
  E --> F["More evictions and restarts"]
  F --> C
        
FIG 5 — How one pressured node can turn into a cluster-wide cascade
ANTI-PATTERN-01 Avoid
Problem

Running every node at very high memory density with large gaps between requests and limits and no spare capacity anywhere.

Why It’s Harmful

Any single failure forces pods onto nodes that are already nearly full, which triggers more evictions and creates a chain reaction.

Correct Approach

Keep headroom across the fleet, set memory requests close to real usage, and test what happens when one node disappears.

i
Plan for N Minus One

Size the cluster so that the loss of one node, or one failure zone, still leaves enough room for the displaced pods. If you cannot survive one failure, your overcommit level is too high.

14The CPU Limit Debate

Should you set CPU limits at all? Experienced teams disagree, and understanding both sides is part of mastering overcommitment.

Because CPU limits cause throttling even when the machine is idle, many experienced engineers recommend setting CPU requests carefully but leaving CPU limits off for most workloads. Their reasoning is that CPU is compressible, requests already guarantee a fair share when the node is busy, and limits only add pauses when there is spare capacity that could have been used for free.

Other teams keep CPU limits for good reasons. Limits give predictable behavior, which is valuable for performance testing. They stop a runaway program from consuming a whole node. And they are required to reach the Guaranteed class, which has special benefits such as exclusive CPU cores when the node uses a static CPU management policy.

Reasons to Skip CPU Limits

  • No throttling when the node has idle CPU
  • Better latency for bursty services
  • Requests still protect fair sharing under load
  • Higher utilization from unused CPU

Reasons to Keep CPU Limits

  • Predictable performance for testing and capacity work
  • Protection against a runaway process
  • Needed for the Guaranteed class
  • Useful fairness in shared multi-tenant clusters
Simple Analogy

A highway can have a speed limit sign even on an empty road at midnight. The sign keeps everyone predictable but it also slows a driver who could have gone faster safely. Removing signs works well on a quiet road and badly in a busy city. The right choice depends on who shares your road.

A sensible middle path

1

Always set CPU requests

They drive scheduling and fair sharing, and they are never optional for serious workloads.

2

Use generous CPU limits or none for latency-sensitive services

Avoid throttling where response time matters most.

3

Use tight limits for batch and untrusted workloads

Protect neighbors from jobs that would otherwise consume everything.

4

Watch throttling metrics

Measure how often containers are paused before and after any change.

15Memory Strategy: Make Requests Match Reality

For memory, the safest overcommit strategy is to be honest in requests and generous but not unlimited in limits.

Because memory cannot be squeezed, overcommitting it is far riskier than overcommitting CPU. A widely used practice is to set the memory request equal to the memory limit for important workloads. This removes burst room for memory, so the pod’s maximum use is known to the scheduler, and the node cannot be surprised by the pod growing past what was counted. Such pods may still be Burstable if CPU is configured differently, but their memory behavior is fully predictable.

Simple Analogy

When you book a hotel room for a family, you tell the hotel exactly how many people are coming. If you say two and bring six, the hotel’s plan breaks. Setting memory request equal to limit is telling the hotel the real family size from the start.

How to choose the memory request

A good starting point is to observe the real memory usage of the application over a typical busy period, including startup and any scheduled heavy tasks, and set the request to cover its normal peak with a small margin. If you set it too low, the node counts too little and packs too many pods. If you set it too high, you waste money, but the pod is safe.

How to choose the memory limit

Choose a limit that is above the highest healthy usage but not so far above that a bug could eat a whole node. Programs written in languages that manage memory automatically need extra care. Their own settings for how much memory they may take should be aligned with the container limit, otherwise the program may believe it has more memory than the container allows and be killed unexpectedly.

Example: The runtime that did not know its limit

A service runs on a machine with plenty of memory, and its runtime sizes its heap based on the whole machine. Inside a container with a smaller limit, the heap grows beyond that limit and the container is killed again and again. Teaching the runtime about the container limit fixes the restarts.

!
Common Mistake

Setting a memory limit far above the request on many pods creates large hidden overcommitment. Everything looks fine until usage grows together, and then nodes run out of memory with no warning from the scheduler.

i
Practical Rule

Overcommit CPU freely for flexible workloads. Overcommit memory only with a clear reason, a measured margin and a plan for what happens when the bet loses.

16Guardrails: LimitRange and ResourceQuota

Good habits are easier when the platform enforces them. Kubernetes offers two namespace-level tools for exactly that.

Asking every developer to write sensible requests and limits works for a while, and then someone forgets. Two built-in tools help the platform team make good behavior automatic. A LimitRange sets defaults and boundaries for each pod or container in a namespace. A ResourceQuota sets a total budget for the whole namespace.

Tool 1

LimitRange

Gives containers default requests and limits when they forget, and sets minimum and maximum sizes, and can control the allowed ratio between limit and request.

Tool 2

ResourceQuota

Caps the total requests, total limits, number of pods and other objects that a namespace may use, so one team cannot take the whole cluster.

Simple Analogy

A LimitRange is the rule that every guest at a buffet gets a standard plate and may not take more than a certain amount in one go. A ResourceQuota is the budget given to each table so that one table cannot clear the whole buffet. Both rules together keep the meal fair.

Controlling the overcommit ratio

The LimitRange can set a maximum ratio between limit and request. For example, a platform team may say that no container may have a memory limit more than one and a half times its request. This is a very direct way to cap overcommitment, because it prevents the huge gaps that create hidden risk. Different namespaces can have different ratios, so a sandbox can be generous while production is strict.

1

Set defaults

Make sure no pod ends up as BestEffort by accident, because defaults fill in missing values.

2

Set minimum and maximum sizes

Prevent tiny, unrealistic requests and giant, wasteful ones.

3

Cap the limit-to-request ratio

Bound how much hidden overcommit any one pod can create.

4

Add a namespace quota

Give each team a total budget so the cluster stays fair overall.

!
Defaults Are Powerful and Dangerous

A default applied to many pods silently becomes the real size of your cluster. A poorly chosen default, repeated across hundreds of pods, will skew every capacity number you have. Review defaults as carefully as any other important setting.

17Right-Sizing with Autoscalers

Humans are bad at guessing resource needs. Automatic tools can watch real usage and suggest better numbers.

Few people can predict how much CPU and memory an application will use. They usually guess high, and the guess becomes permanent. Kubernetes has several autoscaling tools that adjust capacity based on what really happens, and each works on a different level.

Tool 1

Horizontal Pod Autoscaler

Adds or removes copies of a pod based on usage compared with the request. It scales out when load grows.

Tool 2

Vertical Pod Autoscaler

Watches real usage and recommends, or applies, better request values for each container.

Tool 3

Cluster autoscaling

Adds or removes whole nodes when pods cannot be placed or nodes sit underused.

Tool 4

In-place resizing

A newer capability that lets a running pod’s resource values change without recreating it. Its maturity depends on your Kubernetes version, so check the release notes.

flowchart LR
  A["Real usage over time"] --> B["Vertical autoscaler: right size each pod"]
  A --> C["Horizontal autoscaler: right number of pods"]
  B --> D["Accurate requests"]
  C --> D
  D --> E["Cluster autoscaler: right number of nodes"]
        
FIG 6 — Three layers of autoscaling working together
Simple Analogy

A restaurant adjusts three things: how big each table should be, how many tables are set out, and how many dining rooms are open. The vertical tool resizes tables, the horizontal tool adds tables, and the cluster tool opens or closes rooms. A smart manager uses all three.

Be careful when mixing them

The horizontal autoscaler uses usage as a percentage of the request. If the vertical autoscaler keeps changing the request on the same metric, the two can chase each other and cause unstable behavior. A common rule is to avoid letting both act on the same resource for the same workload, or to use the vertical tool only in recommendation mode and apply its advice through your normal review process.

i
Start With Recommendations

Run the vertical autoscaler in recommendation mode first. It will show you which pods are wildly over-requested, which gives you a safe, evidence-based list of savings without any automatic restarts.

18Node Size, Bin Packing and Density

Choosing the size of your machines changes how much overcommitment you can survive.

Fitting pods onto nodes is a packing puzzle called bin packing. Think of nodes as boxes and pods as items of different sizes. Your goal is to fill the boxes well without breaking any. The size of the box matters a great deal. Small boxes waste more space on overhead and leave awkward gaps, and big boxes pack tightly but make each box failure more painful.

ChoiceBenefitsRisks
Many small nodesA single node failure affects few pods, and scaling is fine grainedReserved overhead is a larger share, and large pods may not fit
Few large nodesBetter packing, lower overhead share, room for big podsA failure removes many pods at once, and noisy neighbors multiply
Mixed poolsMatch node shape to workload typeMore pools to operate and monitor
Simple Analogy

Packing a moving truck is easier with a mix of large and small boxes, but if you put everything in one giant crate, losing that crate loses everything. Splitting belongings across several medium boxes is a sensible compromise between easy packing and safe travel.

Match nodes to workload shape

Some workloads need a lot of memory for each unit of CPU, such as caches and databases. Others need a lot of CPU for each unit of memory, such as encoding and calculation. If your nodes have a fixed ratio between the two that does not match the workload, one resource runs out while the other sits idle. This is called stranded capacity. Choosing machine families whose CPU to memory ratio fits the workload recovers real money.

Example: Stranded memory

A team runs CPU-heavy services on nodes with lots of memory. CPU requests fill each node while half the memory remains unused and unusable. Switching to nodes with less memory per CPU lowers cost without any change to the applications.

i
Density Is a Dial

Pods per node is one of the simplest dials for overcommitment. Raising it saves money and raises risk. Measure the effect on latency, restarts and evictions every time you turn it.

19Priority and Preemption

When room runs out, some pods matter more than others, and Kubernetes lets you say which.

A priority class is a named number that you attach to pods. Higher numbers mean more important. Priority affects two moments. When the scheduler cannot find room for an important pod, it can preempt, which means it removes one or more lower-priority pods from a node to make room. And when a node is under pressure, priority is one of the factors the kubelet uses to decide whom to evict.

Simple Analogy

A hospital emergency room treats the most urgent patient first, even if others arrived earlier. If the beds are full and an ambulance brings a critical case, a stable patient is moved to a waiting area. Priority classes give your cluster the same triage rules.

Tier 1

System critical

Components that keep the cluster itself working. These should almost never be displaced.

Tier 2

Business critical

Customer-facing services and databases that must stay up.

Tier 3

Standard

Ordinary internal applications that can tolerate short disruption.

Tier 4

Opportunistic

Batch jobs and experiments that use spare capacity and are happy to be displaced.

Priority makes overcommit safer

A powerful pattern is to fill leftover capacity with low-priority work. These pods use space that would otherwise be idle, so utilization rises. When an important pod needs room, the low-priority pods are preempted and the important pod is placed quickly. You get the money savings of high utilization while the important workloads stay protected.

!
Do Not Mark Everything Critical

If every team labels its pods as the most important, the labels mean nothing, and preemption becomes chaos. Restrict who may use the highest priority classes, and keep the number of tiers small and well documented.

ANTI-PATTERN-02 Avoid
Problem

Giving all workloads the same high priority so that nothing is ever displaced.

Why It’s Harmful

When the node is pressured, the kubelet has no useful ordering to follow, and important pods are evicted at random alongside unimportant ones.

Correct Approach

Define a small set of tiers, give batch and experimental work low priority, and protect high tiers with approvals.

20Swap and Newer Memory Features

Kubernetes has long avoided swap, but the story is changing, and it is worth understanding why.

Swap is disk space that the operating system can use as emergency memory. When real memory runs low, less used data is written to the disk to make room. Disk is much slower than memory, so a heavy swapper feels sluggish, but it may survive where it would otherwise be killed. For years, Kubernetes required nodes to have swap turned off, because it made resource accounting unpredictable, and a pod using swap breaks the clean idea that a memory limit is a hard wall.

More recently, Kubernetes has added optional, controlled swap support that is designed to be safer, with swap offered mainly to pods in certain classes. Details such as which classes are eligible, default behavior and feature maturity have changed from release to release. Always check the documentation for your version before relying on it.

Simple Analogy

Swap is like keeping overflow boxes in the garage when the house is full. The house stays usable and nothing is thrown away, but fetching a box from the garage takes much longer than reaching a shelf. It is a good emergency valve and a bad everyday storage plan.

Advantages

  • Smooths short memory spikes without immediate kills
  • Lets rarely used memory pages move out of the way
  • Can raise density for some workloads

Disadvantages / Trade-offs

  • Disk is far slower than memory, so latency suffers
  • Makes the meaning of a memory limit less simple
  • Sustained swapping can hide a capacity problem until it becomes severe
  • Feature behavior depends on your Kubernetes version
i
Treat Swap as a Cushion

Use it, if at all, as a short-term cushion for bursts. Alert on sustained swap use, because it means the node needs more memory or fewer pods.

!
Check Your Version

Kubernetes memory-related features, including swap support and improvements to how memory requests are protected by the kernel, are evolving. Treat the concepts here as stable and the exact feature status as something to verify in the release notes.

21Observability: What to Watch

Overcommitment is safe only when you can see the early warning signs.

Because overcommitment depends on real usage staying below real capacity, monitoring is not a nice extra. It is the safety system. The signals fall into four families: how full the node is, how hard containers are being squeezed, how often pods are being removed, and how accurate your requests are.

Family 1

Node fullness

Memory and CPU usage as a share of allocatable, plus free disk and process slots. Watch high percentiles over time.

Family 2

Squeeze signals

CPU throttling rates for containers and pressure indicators from the kernel that show how long tasks wait for resources.

Family 3

Removal events

Counts of evictions, out-of-memory kills, node pressure conditions and pod restarts.

Family 4

Request accuracy

Usage compared to requests for each workload, which shows padding and under-sizing.

Simple Analogy

A pilot watches fuel, altitude, engine temperature and weather together. One gauge alone can mislead, but all four together tell the whole story. Node fullness, squeeze, removals and accuracy are your cockpit gauges.

Pressure stall information

Modern Linux kernels can report how much time tasks spend waiting because a resource is short. This is called pressure stall information. It is more honest than a usage percentage, because a node can show moderate usage while tasks still wait. If CPU, memory or disk pressure numbers start rising, the node is already hurting even if it has not crossed an eviction threshold.

1

Dashboards for trends

Show requests, limits and usage per node and namespace over weeks to reveal slow growth.

2

Alerts for danger

Page people for node pressure conditions, repeated out-of-memory kills and rising eviction counts.

3

Reports for cost

Share a regular list of the most over-requested workloads so owners can fix them.

i
Alert on Symptoms Users Feel

Combine resource alerts with latency and error alerts for your applications. A throttled service may show no node alarm at all but still make customers wait.

22Isolating Workloads with Node Pools

Not every workload should share a node. Separating them is the simplest way to control the blast radius of overcommitment.

A node pool is a group of nodes with the same shape and purpose. By using labels, taints and tolerations, you can steer pods onto the pool that suits them and keep unlike workloads apart. This lets you run aggressive overcommitment where failure is cheap and conservative settings where failure is costly.

flowchart TD
  A["Cluster"] --> B["Critical pool: Guaranteed pods, no overcommit"]
  A --> C["General pool: Burstable pods, moderate overcommit"]
  A --> D["Batch pool: BestEffort and low priority, high overcommit"]
        
FIG 7 — Different overcommit levels in different node pools
Simple Analogy

An airport has separate terminals for passengers, cargo and private jets. Each terminal has rules suited to its traffic, and a delay in cargo does not stop the passengers. Node pools are terminals for your workloads.

Pool for databases and critical services

Run Guaranteed pods with requests equal to limits. No burst room and no surprises. Reserve extra headroom on these nodes.

Pool for general applications

Run Burstable pods with moderate gaps between requests and limits. Overcommit CPU more than memory.

Pool for batch and experiments

Run low-priority work that can be interrupted. Use high density and accept preemption, since any loss is cheap.

!
Too Many Pools

Every extra pool adds management work and strands capacity inside small groups. Start with a handful of pools that match real differences in risk, and add more only when evidence demands it.

23Multi-Tenant Fairness and Cost Accountability

When many teams share a cluster, overcommitment is not only a technical question. It is a question of who pays and who is protected.

In a shared cluster, a team that over-requests wastes money that everyone else’s bill carries, and a team that under-requests pushes risk onto its neighbors. Without feedback, teams have little reason to improve. Cost visibility changes behavior: when each team can see how much of its requested capacity it actually uses, over-requesting becomes something people notice and fix.

Practice 1

Show requested versus used

Give every team a simple view of requests, usage and the money wasted by the difference.

Practice 2

Charge by request

Because requests decide how much of the node a pod blocks, chargeback based on requests aligns cost with the capacity taken from others.

Practice 3

Set namespace quotas

Budgets stop one team from absorbing the cluster and encourage planning.

Practice 4

Review regularly

A monthly review of the top over-requested workloads keeps padding from creeping back.

Simple Analogy

Housemates who split the electric bill by the number of lights each has installed will quickly learn to take fewer lights. Splitting by requested capacity does the same for pods: people ask for what they need when asking has a price.

i
Make It Friendly

Present waste reports as helpful suggestions with ready-to-apply numbers, not as blame. Teams respond to clear, easy savings far more than to scolding.

24Design Patterns and Anti-Patterns

Experienced teams keep meeting the same good and bad shapes. Learn them early.

Patterns that work

Pattern 1

Honest requests

Set requests from measured usage so the scheduler’s picture of the node matches reality.

Pattern 2

Memory equal, CPU flexible

Set memory request equal to limit for predictability, and allow CPU to burst.

Pattern 3

Fill gaps with low priority

Use idle capacity for interruptible batch work that yields to important pods.

Pattern 4

Reserve for the system

Always keep space for the operating system, the kubelet and the runtime.

Pattern 5

Separate by risk

Use node pools so critical and experimental workloads do not share a fate.

Pattern 6

Guardrails by default

Use LimitRange defaults and quotas so good behavior needs no effort.

Patterns that hurt

ANTI-PATTERN-03 Avoid
Problem

Leaving requests empty and relying on the cluster to sort it out.

Why It’s Harmful

The scheduler sees these pods as free, so it packs far too many on one node. They become first in line for eviction and still consume real resources.

Correct Approach

Require requests through defaults and policy so nothing runs as BestEffort by accident.

ANTI-PATTERN-04 Avoid
Problem

Copying the same request and limit values from a template into every service.

Why It’s Harmful

Services have very different needs. Some are starved and some are padded, and all capacity numbers become misleading.

Correct Approach

Size each workload from its own measured usage and revisit the numbers regularly.

ANTI-PATTERN-05 Avoid
Problem

Tuning once at launch and never looking again.

Why It’s Harmful

Applications change, traffic grows and numbers drift. A setting that was safe last year becomes either wasteful or dangerous.

Correct Approach

Schedule reviews and use autoscaling recommendations to keep requests current.

25A Step-by-Step Playbook for Safe Overcommitment

If you are starting from a messy cluster, here is a calm order of work that raises efficiency without breaking anything.

1

Measure the current state

Collect requests, limits and usage per workload and per node. Find the biggest gaps and the nodes closest to pressure.

2

Fix the dangerous items first

Find BestEffort pods and pods with tiny requests but large usage. Give them honest requests before anything else, since they create hidden risk.

3

Set up reservations and thresholds

Make sure every node reserves space for the system and has sensible eviction thresholds.

4

Add guardrails

Roll out default sizes, ratio limits and namespace quotas in warning-friendly steps.

5

Right-size the padded workloads

Lower over-large requests gradually, starting with non-critical services, and watch latency and restarts.

6

Introduce priorities and batch filling

Give low-priority work a place in the spare capacity so utilization rises safely.

7

Test failure

Drain a node in a test window and watch whether the cluster absorbs it without a cascade.

8

Repeat on a schedule

Keep measuring and adjusting. Overcommitment is a habit, not a one-time project.

Simple Analogy

Tuning a car engine is done in small steps, checking the results after each change. Nobody replaces ten parts at once and hopes for the best. The same patience applies to resource tuning.

i
Change One Thing at a Time

When several settings change together, you cannot tell which one helped or hurt. Make one change, wait through a full traffic cycle, and compare before making the next.

26Troubleshooting Like a Detective

Most overcommitment problems show up as one of four complaints. Each has a short list of checks.

Complaint 1: “My pod keeps restarting”

1

Read the last termination reason

An out-of-memory reason means the container passed its memory limit. Other reasons point to application errors instead.

2

Compare usage with the limit

If usage climbs steadily to the limit, suspect a memory leak or a limit that is too small for the workload.

3

Check the runtime’s own memory settings

Make sure the application knows about the container limit and does not size itself to the whole machine.

Complaint 2: “My pod was evicted”

Read the status message, which names the signal, such as low memory or low disk. Then check node conditions and recent usage on that node. Look at the pod’s class and how far above its request it was running. If eviction repeats, either raise the request so the pod is better protected and the scheduler places it on a roomier node, or reduce density on the nodes.

Complaint 3: “My service is slow but nodes look idle”

Look for CPU throttling on the container. A tight CPU limit can pause a container even while the node is quiet. Compare the limit with the container’s peak needs. Consider raising the limit or removing it for latency-sensitive services, then watch the throttling metrics fall.

Complaint 4: “Pods are pending though the cluster looks empty”

The scheduler counts requests, not usage. Nodes may be fully requested even though they are mostly idle. Find the over-requested workloads and right-size them, or add capacity if the requests are accurate.

Symptom

Restarts

Suspect memory limits, leaks or runtime settings.

Symptom

Evictions

Suspect node pressure, low requests or high density.

Symptom

Slowness

Suspect CPU throttling or noisy neighbors.

Symptom

Pending pods

Suspect padded requests or true lack of capacity.

Simple Analogy

A good mechanic listens to the complaint, checks the simplest causes first, and only then opens the engine. Following the cheap checks in order saves hours of guessing.

i
Write the Runbook Once

Turn these four complaints into a one-page runbook for your support channel. Teams that can diagnose the common cases themselves free the platform team for the hard problems.

27Exclusive CPUs: When Overcommit Is Switched Off

For the most sensitive workloads, Kubernetes can give a pod its own private CPU cores that nobody else may touch.

Normally, many pods share all the CPU cores of a node, and the kernel moves their work around freely. That sharing is what makes CPU overcommitment possible. But some applications, such as trading systems, telephone switching and high-speed packet processing, suffer when their work keeps moving between cores. For them, a node can run a static CPU management policy. Under this policy, a pod in the Guaranteed class that asks for a whole number of CPUs is given exclusive cores, and other pods are kept off those cores.

Simple Analogy

A shared office has hot desks that anyone may use, which keeps costs low. A few specialists, such as a surgeon in a hospital, get their own private room with their own equipment because interruption would be too costly. Exclusive CPUs are the private rooms of a cluster.

Advantages

  • Very steady performance with little interference
  • No CPU throttling from neighbors competing for the same core
  • Better use of processor caches for sensitive code

Disadvantages / Trade-offs

  • Reserved cores cannot be shared even when idle
  • Lower overall utilization and higher cost
  • Only suits whole-number CPU requests in the Guaranteed class
  • Needs separate nodes or careful planning
i
Use Sparingly

Exclusive cores are the opposite of overcommitment. Use them only where measured performance proves they are needed, and place those workloads in their own node pool.

28Headroom, Failure Zones and Capacity Planning

The right amount of overcommitment depends on how much spare room you keep for bad days.

Headroom is the unused capacity you deliberately keep. It absorbs traffic spikes, node failures and rollouts. A cluster with no headroom has no way to survive an unexpected event. A cluster with huge headroom wastes money. The art of capacity planning is picking the smallest headroom that still lets you survive your realistic worst days.

Think in failure zones

Cloud clusters are often spread across several failure zones, which are separate data center areas. If one zone fails, all the nodes there disappear together, and their pods must be placed on the remaining zones. If you have three zones and run each at high density, the loss of one zone requires the other two to absorb fifty percent more load. That is impossible if they were already near full. This simple arithmetic tells you how much headroom to keep.

Number of ZonesLoad Increase on Survivors if One Zone FailsMaximum Safe Average Fullness
2DoublesAbout half
3One and a half timesAbout two thirds
4One and a third timesAbout three quarters
Simple Analogy

If a restaurant has three dining rooms and one room must close, the other two rooms must hold all the guests. The restaurant can only promise that if each room is at most two thirds full on a normal night. Headroom is the empty seats that make the promise true.

Other uses of headroom

Use 1

Traffic spikes

Sudden growth in demand needs spare room while new nodes are still starting.

Use 2

Rolling updates

Updates briefly run old and new pods together, which needs temporary extra capacity.

Use 3

Node maintenance

Draining a node for upgrades pushes its pods elsewhere.

Use 4

Autoscaler delay

New nodes take minutes to appear. Headroom covers the gap.

!
Autoscalers Are Not Instant

Cluster autoscaling reacts to pods that are already pending, and adding a node takes time. If your overcommit plan assumes new nodes will arrive instantly, a sharp spike can still cause pressure and evictions before help arrives.

i
Spare Placeholders

Some teams run low-priority placeholder pods that hold spare room. When real work arrives, the placeholders are preempted and real pods start instantly while the autoscaler adds new nodes behind the scenes.

29Best Practices and Common Mistakes

A short checklist of habits that separate calm clusters from stressful ones.

Best Practices

  • Set requests for every container from measured usage
  • Keep memory requests equal to limits for important workloads
  • Reserve space for the system on every node
  • Use priority classes and fill gaps with interruptible work
  • Apply LimitRange defaults and namespace quotas
  • Watch throttling, pressure, evictions and out-of-memory kills
  • Keep headroom for losing a node or a zone

Common Mistakes

  • Leaving requests empty and creating BestEffort pods
  • Large gaps between memory request and limit
  • Tight CPU limits on latency-sensitive services
  • Ignoring disk and process-slot limits
  • Sizing from averages instead of peaks
  • Running every node near full
  • Tuning once and never revisiting

Three questions before changing any number

1

What does the evidence say?

Look at real usage over a long enough window including peaks. Do not tune from a hunch.

2

What happens if the bet loses?

Decide whether the worst case is a slow page, a restart or lost data, and tune the risk to match.

3

How will we know quickly?

Make sure an alert or dashboard will show the effect of the change within minutes.

i
Start With the Cheap Win

The easiest saving in most clusters is lowering padded CPU requests on non-critical services. It carries little risk, because CPU is compressible, and it frees real capacity quickly.

!
Do Not Chase Utilization Alone

A cluster running at ninety percent usage can look wonderful on a cost dashboard and be one traffic spike away from an outage. Efficiency must always be balanced against reliability.

30Real-World and Industry Examples

Different industries accept different levels of overcommitment because their cost of failure differs.

Online retail: seasonal peaks

A shop runs its checkout and payment services with generous memory requests and low overcommit, while search, recommendations and image processing run with more burst room. Before a big sale, the team raises headroom, because correlated demand is exactly the situation that breaks overcommit bets.

Streaming media: batch encoding on spare capacity

A video company fills idle capacity with low-priority encoding jobs that use whatever CPU is free. When live-streaming pods need room, the encoding jobs are preempted. Utilization stays high, and viewers never notice.

Financial services: strict isolation for critical systems

A bank puts trading and payment systems on dedicated nodes with Guaranteed pods and sometimes exclusive CPUs. Reporting and analytics, which tolerate delay, share a heavily overcommitted pool. Risk is matched to the business cost of failure.

Software platform: internal developer environments

A company with hundreds of developers runs short-lived test environments with tight quotas and high overcommit. Idle environments are cleaned up automatically, and the cost of an occasional slow test is small compared with the savings.

Machine learning: expensive hardware and mixed jobs

A data team runs training jobs on costly accelerator nodes with exact requests and no overcommit for the scarce hardware, while data preparation steps use cheaper pools with relaxed settings.

“Overcommit where failure is cheap, and be strict where failure is expensive.”

31Inside the Node: How the Kernel Enforces Your Numbers

Kubernetes writes the numbers down, but the Linux kernel is the one that actually enforces them.

Kubernetes itself does not slow down or stop containers. It translates the requests and limits you wrote into settings for a Linux feature called control groups, usually shortened to cgroups. A control group is a labeled bucket that the kernel keeps around a set of processes. The kernel tracks how much CPU, memory and other resources each bucket is using and applies the rules attached to that bucket. Every container gets its own bucket, every pod gets a larger bucket that holds its containers, and quality-of-service classes get buckets above that.

flowchart TD
  A["Node root bucket"] --> B["Guaranteed pods bucket"]
  A --> C["Burstable pods bucket"]
  A --> D["BestEffort pods bucket"]
  C --> E["Pod bucket"]
  E --> F["Container bucket with limit settings"]
        
FIG 8 — The bucket hierarchy the kernel uses to enforce resource rules
Simple Analogy

Think of a school where each class has a locker room, each student has a locker, and the principal’s office keeps a rule sheet for each one. The teachers do not enforce locker size; the janitor, who is the kernel, checks every locker against its rule sheet. Kubernetes writes the rule sheets, and the kernel does the checking.

What each setting becomes

Kubernetes SettingWhat the Kernel ReceivesWhat You Feel
CPU requestA relative weight for sharing timeFair share when the node is busy
CPU limitA time quota per short windowThrottling once the quota is used
Memory requestMostly a scheduling number, plus an input to how likely a process is to be chosen as a victimBetter protection when memory is short
Memory limitA hard memory ceiling for the bucketOut-of-memory kill when exceeded

Why a memory request is not a reservation

Many people believe that a memory request puts that memory aside for the pod. By default it does not. The kernel does not hold physical memory back for a container just because it asked. The request is used by the scheduler to count room and by the node to rank pods under pressure. This is one more reason why the real usage of all pods, not only the sum of requests, decides whether a node is safe.

!
Version Note

Newer Kubernetes releases have been adding optional features that make the kernel protect memory requests more actively. Their status changes between versions, so confirm in the release notes before depending on them.

i
Why This Matters

When a surprising slowdown or kill happens, knowing that the kernel is the real enforcer tells you where to look: kernel counters about throttling, memory events and pressure are the ground truth behind every dashboard.

32A Worked Example with Real Numbers

Numbers make the ideas stick. Let us follow one small node from empty to overcommitted.

Imagine a node with sixteen gigabytes of memory and eight CPU cores. The team reserves one gigabyte of memory for the system and the kubelet, and keeps a half gigabyte as an eviction margin. That leaves fourteen and a half gigabytes of allocatable memory. Suppose seven cores are allocatable on the CPU side after similar reservations.

16 GB
Node memory capacity
14.5 GB
Allocatable memory
7 cores
Allocatable CPU

Step 1: Place the pods

The team places ten identical pods on the node. Each asks for one gigabyte of memory and half a core as a request, and has a limit of two gigabytes and one core. The scheduler adds up requests: ten gigabytes of memory and five cores. That fits inside fourteen and a half gigabytes and seven cores, so all ten pods are accepted, and there is still room for a few more.

Step 2: Count the promises

Now add up the limits. Ten pods with two gigabyte limits make twenty gigabytes of memory limit. Ten pods with one core limits make ten cores of CPU limit. Compared with allocatable, the memory limit total is about one hundred and thirty-eight percent and the CPU limit total is about one hundred and forty-three percent. The node is overcommitted on both resources, even though requests show it is only about seventy percent full.

MeasureMemoryCPUPercent of Allocatable
Sum of requests10 GB5 coresAbout 69 percent memory, 71 percent CPU
Sum of limits20 GB10 coresAbout 138 percent memory, 143 percent CPU
Typical real usageAbout 7 GBAbout 2 coresAbout 48 percent memory, 29 percent CPU

Step 3: Watch a good day and a bad day

1

A normal day

Usage stays near seven gigabytes and two cores. Nothing is throttled, nothing is evicted. The overcommit saved money and nobody noticed it.

2

A busy CPU day

Traffic doubles and the pods want five cores in total. That fits within seven allocatable cores, so each pod is only slowed a little by sharing. CPU overcommit is forgiving.

3

A bad memory day

A bug makes six pods grow toward their two gigabyte limits at once. Together they want twelve gigabytes, plus the other four pods’ normal use, which brings the total above fifteen. That is more than allocatable. The node crosses its threshold and the kubelet begins evicting pods that are above their request.

Simple Analogy

Ten guests were each promised a seat at a table plus the right to borrow one extra chair. On a normal night, hardly anyone borrows. If six guests all borrow a chair at the same moment, the room runs out of chairs. The extra-chair rule worked until demand lined up.

i
What the Example Teaches

The same node was perfectly safe for CPU and risky for memory. This is why many teams keep memory requests equal to limits and let only CPU have burst room.

33Overcommitment and Cloud Cost Strategy

Overcommitment is one lever in a larger cost story, and it works best together with the others.

Cloud bills depend on how many machines you rent, what kind they are and how you pay for them. Overcommitment reduces the number of machines by packing more work onto each one. But there are other levers, and they interact. Understanding how they fit together helps you choose where overcommitment belongs.

Lever 1

Right-sized requests

Cuts waste by making the scheduler’s numbers honest. The safest saving and the first to try.

Lever 2

Higher density

Allows more pods per node through overcommit. Larger saving, larger risk.

Lever 3

Discounted interruptible machines

Cloud providers rent spare machines at lower prices, with the right to take them back. Good for work that tolerates interruption.

Lever 4

Committed use discounts

Paying for a steady base load in advance lowers the unit price for capacity you know you will always need.

Simple Analogy

To lower a household budget you can buy less, share more, buy in bulk and shop sales. No single trick does it all. A clever family combines them: a steady monthly plan for what it always needs and cheap, flexible options for what it sometimes needs.

Matching levers to workloads

Workload TypeSuggested MachinesOvercommit Level
Steady critical servicesCommitted, reliable machinesLow
Variable web servicesReliable machines with autoscalingModerate, mostly CPU
Interruptible batch workDiscounted interruptible machinesHigh, with low priority
Development environmentsSmall or discounted machinesHigh, with quotas
!
Double Risk

Combining high overcommit with interruptible machines multiplies risk, because the provider can remove a machine at any time and the remaining machines must absorb the pods while already packed tightly. Use that combination only for work that restarts cheaply.

i
Savings Need Proof

Measure the bill before and after each change, and watch reliability metrics at the same time. A saving that causes more incidents is not a saving.

34Resource Abuse and Security Considerations

Resources are also a security topic, because a program that can use unlimited resources can hurt everyone around it.

On a shared node, a program that consumes too much memory, too many processes, too much disk or too much processor time can deny service to its neighbors. This can happen by accident, as in a bug, or on purpose, as in an attack. In a cluster where teams do not fully trust each other, or where customers run their own code, resource limits are a security control as much as a cost control.

Simple Analogy

In an apartment building, one tenant who leaves every tap running can flood the floors below. Building rules about water use protect everyone, whether the tenant is careless or malicious. Resource limits are the water rules for a shared node.

Threat 1

Memory exhaustion

A pod without a memory limit grows until the node is under pressure and neighbors are evicted.

Threat 2

Process flooding

A program creating huge numbers of processes can use up the node’s process slots.

Threat 3

Disk filling

Writing endless data to temporary storage can trigger disk pressure and evictions.

Threat 4

CPU hogging

A busy loop can crowd out neighbors on nodes where requests are low and limits absent.

Defensive habits

1

Require limits for untrusted workloads

Any code you do not fully control should run with firm limits on memory, storage and processes.

2

Use namespace quotas

Cap total consumption per team or customer so one tenant cannot take the whole cluster.

3

Isolate in separate pools

Put the riskiest workloads on their own nodes so the blast radius is small.

4

Enforce rules with admission policy

Use an admission controller or policy engine to reject pods that arrive without requests and limits, so nobody can forget.

ANTI-PATTERN-06 Avoid
Problem

Allowing tenants or customers to run workloads with no memory limit on shared nodes.

Why It’s Harmful

One buggy or hostile workload can push the node under pressure, causing evictions of unrelated neighbors and turning a small mistake into a platform outage.

Correct Approach

Require limits through defaults and policy, apply quotas, and isolate unfamiliar code in dedicated pools.

35Reading the Units: Millicores and Mebibytes

Half the confusion about resources comes from the units. A short lesson in reading them removes a lot of mistakes.

Kubernetes measures CPU in cores and fractions of cores. One whole core is written as one. A tenth of a core is written as one hundred millicores, where a millicore is a thousandth of a core. So five hundred millicores is half a core, and two thousand millicores is two cores. A container asking for a tiny amount, such as ten millicores, wants only a hundredth of one core, which is enough for a very quiet helper process.

Memory is measured in bytes, with friendly suffixes. There are two families of suffixes, and mixing them up causes quiet errors. The decimal family uses powers of one thousand, and the binary family uses powers of one thousand and twenty-four. A mebibyte is slightly larger than a megabyte, and a gibibyte is slightly larger than a gigabyte. The difference is small for small numbers but grows as numbers grow, and a limit written in one family can be a few percent different from the same-looking number in the other.

You WriteIt MeansPlain Words
500 millicores0.5 coresHalf of one core
2 cores2000 millicoresTwo full cores
256 mebibytes268,435,456 bytesA quarter of a gibibyte
1 gibibyte1,073,741,824 bytesAbout 7 percent more than a decimal gigabyte
Simple Analogy

Imagine two shops that both sell a dozen eggs, but one counts a dozen as twelve and the other as thirteen. Everyone thinks they bought the same amount, yet the totals drift apart over many purchases. The two memory suffix families are like those two shops.

Why units cause real incidents

A small typing slip can change a number by a huge factor. A memory limit written with the wrong suffix can become a thousand times smaller than intended, and the container is killed the moment it starts. A CPU request written as a whole number when a fraction was meant can claim many times more room than needed and block other pods. Reviewing the units in a change is as important as reviewing the logic.

!
Easy to Miss

Lowercase and uppercase letters in suffixes can change the meaning of a number completely. Treat unit strings as precise code, not as casual text, and rely on automated checks to catch suspicious values.

i
Make It Visible

Display resources in a consistent unit on dashboards, such as cores for CPU and gibibytes for memory, so humans can compare numbers at a glance without converting.

36Application Runtimes and Container Limits

The program inside the container must understand the box it lives in, or it will misbehave.

Many programs decide how much memory and how many worker threads to use by looking at the machine they run on. Inside a container, the machine they see may be much bigger than the slice they are allowed to use. A program that thinks it owns thirty-two cores may start thirty-two worker threads even though the container is limited to one core, and the result is heavy throttling. A program that thinks it owns a huge amount of memory may grow its internal storage far beyond the container limit and be killed.

Simple Analogy

A guest in a hotel suite looks out of the window at the whole city and assumes the city is theirs, but their key opens only one room. If they plan a party for hundreds of people in a room that holds ten, the party is stopped at the door. A runtime that looks outside its container makes the same mistake.

Runtime Type 1

Managed-memory languages

Languages with automatic memory cleanup keep a heap. If the heap maximum is not tied to the container limit, the heap can outgrow the box. Modern versions of many runtimes read the container limit, but defaults still need checking.

Runtime Type 2

Thread-heavy servers

Servers that create a worker thread per core can start far too many threads when they see the whole machine, causing throttling under a small CPU limit.

Runtime Type 3

Native memory users

Programs that allocate memory outside the managed heap, such as libraries and caches, can exceed a limit even when the visible heap looks healthy.

Runtime Type 4

Short-lived scripts and jobs

Small programs may use a burst of memory at startup that is much higher than their steady use, which must be covered by the limit.

Leave a gap between runtime and limit

A program’s total memory is more than its main heap. It also includes code, thread stacks, buffers and internal bookkeeping. If you set the heap maximum equal to the container limit, the extra pieces push the total over the limit and the container is killed. A common habit is to set the program’s own memory target to a comfortable fraction of the container limit and leave the rest as a safety margin for everything else.

1

Find out what the runtime sees

Check whether your language runtime reads the container’s limits or the machine’s.

2

Tie its settings to the container

Set heap size and thread counts as a fraction of the container’s limits.

3

Leave a margin

Keep part of the limit free for non-heap memory and for short spikes.

4

Test under load

Run a realistic load test inside the real limits and watch for kills and throttling.

i
Test in the Box

An application that runs perfectly on a laptop may fail inside a small container. Always test inside the same limits you plan to use in production.

37Startup Spikes, Probes and Rolling Updates

Many resource incidents happen not in steady state but in the moments when pods start or change.

An application often needs far more CPU and memory in its first seconds than later. It loads code, warms caches, opens connections and sometimes compiles parts of itself. If its request is sized for the quiet steady state, the node does not count that startup burst, and when many pods start at once the node can be overwhelmed. This is common during a rolling update, a node drain or after a failure, when many replacement pods start together.

Simple Analogy

A kettle uses lots of power for the first few minutes while it heats, then very little to keep warm. If the whole office switches on its kettles at the same moment every morning, the fuse trips, even though the average power use is low. Startup spikes are the morning kettles of a cluster.

How probes make things worse

Kubernetes uses probes to check whether a container is alive and ready. If a container is slow to start because the node is busy, and the probe gives up too early, Kubernetes restarts the container. The restart causes another startup spike, which keeps the node busy, which slows the next start, and a restart loop can feed on itself. This is a classic way for a mild shortage to become a long outage.

flowchart TD
  A["Node is busy"] --> B["Container starts slowly"]
  B --> C["Probe times out"]
  C --> D["Container is restarted"]
  D --> E["Another startup spike"]
  E --> A
        
FIG 9 — A restart loop that feeds on its own startup cost
Remedy 1

Startup probes

Give slow starters a dedicated, generous startup allowance before normal health checks begin.

Remedy 2

Gentler rolling updates

Limit how many pods are replaced at once so startup spikes are spread out.

Remedy 3

Realistic requests

Size requests to cover startup, or allow generous CPU burst room so starts finish quickly.

Remedy 4

Disruption budgets

Control how many pods of a service may be unavailable during maintenance and evictions.

Example: The Monday morning stampede

After a weekend node upgrade, forty pods restart at once on a handful of nodes. Each needs triple its normal CPU for the first minute. The nodes slow down, probes time out, and pods restart again. Spreading the update into small batches and adding a startup probe ends the stampede.

!
Spikes Break Averages

Capacity plans built on average usage miss startup spikes completely. Look at the busiest minutes during deployments and recoveries, not just calm hours.

38Frequently Asked Questions

Short, direct answers to the questions people ask most often when they first meet node overcommitment.

Q1Is overcommitment bad?

No. It is a deliberate trade-off that saves money by letting workloads share idle capacity. It becomes bad when it is accidental, unmeasured or applied to memory without a safety margin.

Q2Does the scheduler look at limits?

No. The scheduler fits pods using requests only. Limits are enforced later by the node while the container runs, which is exactly why the sum of limits can exceed what the node owns.

Q3What happens when a container exceeds its CPU limit?

It is throttled, meaning it is paused for part of each time window. It is not killed, but it can become noticeably slow.

Q4What happens when a container exceeds its memory limit?

The kernel kills it with an out-of-memory event, and Kubernetes restarts it according to its restart rules.

Q5Which pods are removed first when a node runs low on memory?

Pods using more than their request go first, and among them the lower priority ones, so BestEffort pods and heavily bursting Burstable pods are the first victims. Guaranteed pods are the most protected.

Q6How do I get the Guaranteed class?

Every container in the pod must have both a CPU and a memory request and limit, with the request equal to the limit for each.

Q7Should I remove CPU limits?

Many teams remove them for latency-sensitive services to avoid throttling, while keeping accurate requests. Keep them for batch, untrusted or exclusive-core workloads. Measure throttling before and after any change.

Q8Why are my pods pending when nodes look idle?

The scheduler counts requests, not usage. Nodes can be fully requested yet nearly idle if requests are padded. Right-size the requests to free the room.

Q9How much memory overcommit is safe?

There is no universal number. It depends on how independent your workloads are, how spiky they are and how costly failure is. Keep memory requests close to real usage and overcommit memory only with a measured margin.

Q10Can I limit the gap between limits and requests?

Yes. A LimitRange can set a maximum ratio between limit and request for containers in a namespace, which directly caps hidden overcommitment.

Q11Do autoscalers solve overcommitment automatically?

They help, but they do not replace good requests. They react to usage and pending pods, and they take time. You still need accurate requests, headroom and monitoring.

Q12What is the single most important number to get right?

The request. It decides placement, protection under pressure and the scheduler’s picture of every node, so honest requests make nearly everything else easier.

39Summary and Key Takeaways

Node overcommitment is the practice of promising, through limits, more CPU and memory than a machine can deliver at once, betting that workloads will not all peak together. It saves money because most applications use far less than they could. It is safe when requests are honest, memory is treated with respect, system space is reserved, priorities protect what matters, headroom survives a node or zone failure, and monitoring watches the warning signs. It is dangerous when requests are empty, memory gaps are huge, nodes run near full, and nobody looks at the numbers after launch.

Key Takeaways

  • The scheduler counts requests only — limits and live usage are ignored when placing pods, so the sum of limits is where overcommitment hides.
  • CPU squeezes, memory kills — CPU shortage slows programs, while memory shortage forces something to be stopped, so be bold with CPU and careful with memory.
  • Quality-of-service classes decide who is protected — Guaranteed pods are safest, Burstable pods are ranked by how far they exceed requests, and BestEffort pods go first.
  • Reserve space for the system — allocatable is capacity minus reservations and thresholds, and skipping reservations can starve the node itself.
  • Measure three totals — compare requests, limits and real peak usage against allocatable to see real risk, and judge by peaks rather than averages.
  • Use guardrails and priorities — LimitRange, ResourceQuota, priority classes and node pools make good behavior automatic and contain the blast radius.
  • Keep headroom and revisit often — plan for losing a node or zone, test failures, and review numbers regularly because applications and traffic keep changing.