Capacity Planning in Kubernetes
A plain-English guide to deciding how much computing power your clusters need, where the hidden limits are, how much spare room to keep, and how to prove your plan works before the traffic arrives.
Imagine you run a hotel. If you build too few rooms, guests are turned away on busy weekends and they never come back. If you build far too many, you pay for empty rooms, empty corridors and empty cleaning shifts all year. Good hotel managers do not guess. They count how many guests came last year, notice that weekends and holidays are different, keep a few rooms free for emergencies and plan ahead for the day a big conference comes to town.
Running Kubernetes is surprisingly similar. Your applications are the guests. Your nodes are the rooms. If the cluster is too small, pods wait in a queue, services slow down and users notice. If it is too big, the bill grows quietly while machines sit idle. Between those two failures lies a discipline called capacity planning: working out, with evidence, how much capacity you need, in what shape, with how much safety margin, and by when.
This guide teaches that discipline from the ground up. You will learn how Kubernetes counts resources, why the numbers on a dashboard can mislead you, how to size nodes and headroom, how to work through a complete example, and how to check limits that are easy to forget, such as network addresses and the cluster brain itself. Every new term is explained in simple words and tied to an everyday picture.
1Why Capacity Planning Matters
Capacity is the balance between reliability and cost. Planning it badly makes you pay either way.
Two ways to get it wrong
The first failure is too little capacity. Pods cannot be placed, so they stay in a waiting state. Nodes run hot, so applications slow down or get killed. A traffic spike or the loss of a machine pushes the whole cluster over the edge, and a small problem becomes an outage. These failures are loud and urgent, and they happen at the worst possible moments.
The second failure is too much capacity. Nothing breaks, so nobody complains. But machines sit mostly idle, and the company pays for them every hour. Because the waste is silent, it can last for years. In large organizations, idle capacity often adds up to a very large sum of money.
Think of a restaurant on a Saturday night. With too few tables, a queue forms at the door and customers walk away. With too many tables, the waiters stand around and the rent is wasted. A good manager looks at past Saturdays, expects some surprises and keeps a few spare tables for walk-ins. The manager is doing capacity planning.
Why Kubernetes makes this trickier
Kubernetes adds layers between your application and the machine. A single sentence like “this app needs a lot of memory” becomes a request on a pod, which is placed by a scheduler on a node, which itself has reservations for system programs, which sits in a zone that may fail. Each layer has its own rules, its own counting and its own limits. Capacity planning means understanding all those layers and making them agree.
What a good plan answers
- How much CPU, memory, storage and network will our workloads need at their busiest?
- What shape should the machines have, small or large, balanced or memory-heavy?
- How much spare room do we keep for failures, upgrades and surprises?
- When will we run out if demand keeps growing, and how long does it take to add more?
- What limits other than machines could stop us, such as network addresses or cloud quotas?
- How do we know the plan is right before real users find out?
Capacity planning is not a one-time project. It is a loop that repeats: measure, model, forecast, add a safety margin, test, then measure again. The best teams make it a regular habit, not an emergency reaction.
2Capacity Planning vs Autoscaling
Many people think autoscaling makes planning unnecessary. It does not. The two work at different time scales and answer different questions.
What autoscaling does
Autoscalers react to the present. When load rises, the pod autoscaler adds pods, and the node autoscaler adds machines. When load falls, they remove them. This handles ups and downs within a day or a week very well. But autoscalers can only act inside a box. They need a place to put new machines, permission to create them, money to pay for them and limits that allow it.
What capacity planning does
Capacity planning draws the box. It decides the minimum and maximum size of node groups, which machine types are allowed, how many network addresses are reserved, how big the control plane must be and how much the organization will spend. It also looks far ahead, at the next quarter or the next year, and asks whether the box itself will be big enough.
| Question | Autoscaling | Capacity planning |
|---|---|---|
| Time scale | Seconds to hours | Weeks to years |
| Main job | Follow today’s load | Make sure the limits and budget allow tomorrow’s load |
| Who decides | Controllers, automatically | Engineers and owners, with evidence |
| Typical output | Replica and node counts | Node shapes, minimums, maximums, quotas, budgets, purchase commitments |
| Fails when | Metrics are wrong or limits are hit | Assumptions are wrong or nobody reviews them |
flowchart TB
PLAN["Capacity planning: sets the box"] --> BOX["Node types, min and max sizes, quotas, IP ranges, budget"]
BOX --> AUTO["Autoscalers: move inside the box"]
LOAD["Real traffic changes"] --> AUTO
AUTO --> CLUSTER["Cluster size right now"]
CLUSTER -->|"actual usage and limits hit"| FEEDBACK["Measurements"]
FEEDBACK --> PLAN
Why the lead time matters
Autoscaling can add a cloud machine in minutes, but only if the cloud agrees. If you are close to an account limit, a request for more can take days. In your own data centre, buying and installing servers can take months. Capacity planning is the art of asking early enough that the answer arrives before you need it.
Autoscaling is like opening extra checkout lanes when a queue forms. Capacity planning is deciding how big the shop is, how many lanes can ever be built and whether the car park is large enough for the shoppers. Opening lanes is useless if the shop has no more space for them.
An autoscaler with a maximum that is too low silently stops helping at exactly the moment you need it most. Review those maximums as part of capacity planning, not as an afterthought.
3What Capacity Is Made Of
When people say “capacity”, they usually mean CPU and memory. In practice, many other limits can run out first.
The big four
CPU
Processing power, measured in cores or in thousandths of a core called millicores. Half a core is written as 500m. It is shared among pods on a node.
Memory
Fast working storage, measured in bytes, usually written in mebibytes or gibibytes. A program that runs out of its allowed memory is stopped.
Storage
Disk space and disk speed. This includes the temporary space inside nodes, the container images they hold, and persistent volumes for data that must survive.
Network
Bandwidth, connections, addresses and the capacity of shared services such as DNS and load balancers.
The quiet limits
Beyond these four, there is a second group of limits that rarely appear on dashboards until they bite.
Maximum pods
Each node allows a fixed maximum number of pods, with a common default of 110. Many small pods can fill a node while its CPU is nearly idle.
IP addresses
Every pod needs an address from a limited range. Some cloud networks also cap how many addresses a machine can hold.
Volume attachments
A machine can attach only a limited number of disks. Many stateful pods can hit this long before CPU or memory run out.
API server and database
The cluster brain has its own limits on the number of objects, the rate of requests and the size of its database.
Account quotas
Cloud providers limit how many machines, addresses or load balancers an account may hold in a region.
Budget
The most flexible limit in theory, and often the most rigid one in practice.
The weakest link decides
A cluster is only as large as its tightest limit. You might have plenty of CPU but no free pod addresses, or plenty of memory but no spare disk attachments. The goal of planning is to find the tightest limit for each workload type, and to make sure none of them is a surprise.
Think of a theatre. It may have enough seats, enough lighting and enough staff. But if the fire safety rules limit the crowd to 300 and you sold 400 tickets, the fire rule decides the real capacity. Hidden limits in Kubernetes act the same way.
When you review a cluster, make a short table with every limit, its current use, its maximum and how long it would take to raise. The limits with the smallest remaining room and the longest lead time are your real risks.
4How Kubernetes Counts: Requests, Limits and Usage
This is the single most important idea in the whole guide. Kubernetes plans with promises, not with measurements.
Three different numbers
For every container, three numbers matter, and beginners often mix them up.
Request
The amount you promise the container will need. The scheduler uses this number to find a node with enough free room. It is a reservation, like booking a table for four.
Limit
The most the container is allowed to use. It is a ceiling, enforced by the node. Go above it and you are slowed down for CPU, or stopped for memory.
Usage
What the container is actually using right now. This changes second by second and is measured by monitoring tools. The scheduler does not use it when placing pods.
The scheduler plans with requests
When a new pod arrives, the scheduler adds up the requests of all pods already on each node and subtracts them from what the node can offer. It places the new pod on a node that still has room for the new pod’s requests. Real usage is never consulted. So a node can be fully booked while its CPU is almost idle, or it can be heavily used while the scheduler thinks it has room, if the pods asked for much less than they use.
Picture a cinema with reserved seats. The ticket office sells seats based on bookings, not on whether people actually turn up. If everyone books but half stay at home, the cinema looks full while seats are empty. If the booking system lets people squeeze in without booking, the cinema looks empty while the room is crowded. Requests are the bookings.
flowchart LR
REQ["Pod requests: what was promised"] --> SCHED["Scheduler adds up requests per node"]
SCHED --> FIT{"Does the new pod fit in the remaining requested room?"}
FIT -->|"yes"| PLACE["Pod is placed on the node"]
FIT -->|"no"| PEND["Pod stays Pending"]
PLACE --> RUN["Pod runs and uses real resources"]
RUN --> USE["Usage: measured by monitoring"]
USE -.->|"not used for placement"| SCHED
Two kinds of capacity numbers
Because of this, every cluster has two different pictures. Allocation is what has been promised through requests. Utilization is what is really used. Capacity planning must look at both. Allocation tells you when the scheduler will run out of room. Utilization tells you whether the room is actually busy. The gap between them is the clearest sign of waste or of risk.
Quality of service classes
Kubernetes sorts pods into three classes depending on how their requests and limits are set. These classes decide who is protected and who is sacrificed when a node runs short.
| Class | How it is set | Behavior under pressure |
|---|---|---|
| Guaranteed | Every container has requests equal to its limits for CPU and memory | Most protected. Last to be evicted |
| Burstable | At least one request is set, but not equal to the limit | Middle. Evicted after BestEffort pods, based on how much they exceed their requests |
| BestEffort | No requests or limits at all | First to be evicted. Placement gives no promise of room |
Pods with no requests look free to the scheduler. A cluster full of them appears nearly empty on paper and then collapses under real load. Always set requests, and use defaults and policies to make sure nobody forgets.
5CPU and Memory Behave Differently
The two main resources are not the same kind of thing. Understanding the difference explains most surprises in real clusters.
CPU can be squeezed
CPU is called a compressible resource. If a container wants more processing time than it is allowed, the node does not kill it. It simply gives the container less time, so the program runs slower. This slowing down is called throttling. The node divides processor time into tiny slices, and a container that has used its share for the current slice must wait for the next one.
Throttling is sneaky because nothing crashes. Instead, response times get longer, sometimes in short bursts that average out on a dashboard but hurt real users. A container can be throttled even when the node as a whole is quite idle, if its own limit is low.
Memory cannot be squeezed
Memory is an incompressible resource. Once a program has filled memory with data, the node cannot take it back without destroying the program. If a container goes above its memory limit, the node stops it abruptly. This is called an out-of-memory kill, and the container is then restarted if its pod rules allow. If the whole node runs short of memory, the node starts evicting pods to protect itself.
CPU is like a road. When too many cars arrive, traffic slows down but everyone still gets through eventually. Memory is like seats on a bus. When the bus is full, nobody else can sit, and someone has to get off. Slowing down and being thrown off are very different problems.
| Property | CPU | Memory |
|---|---|---|
| Type | Compressible | Incompressible |
| When the limit is hit | Container is throttled (slower) | Container is killed |
| Sharing when idle | Unused time is easy to share | Held until the program frees it |
| Safe planning style | Plan around typical high percentiles of use | Plan around the peak, plus a safety margin |
| Cost of being wrong | Slow responses | Restarts and lost work |
What this means for planning
Because CPU bends and memory breaks, teams often treat them differently. Many set CPU requests near typical busy usage and are relaxed about CPU limits, while setting memory requests and limits close to the real peak. Programs whose memory is managed by a runtime, such as those with garbage collectors, need extra care because their memory can jump in steps rather than grow smoothly.
The CPU limit debate is real. Some teams avoid CPU limits entirely so that spare processor time is never wasted, relying on requests to guarantee a fair share. Others keep limits to protect neighbours. Whichever you choose, apply it consistently and measure throttling so that it is a decision, not an accident.
Memory limits higher than requests allow a pod to borrow memory that other pods were promised. When several borrowers peak together, the node runs out and somebody is evicted. Overcommitting memory is far riskier than overcommitting CPU.
6Node Capacity vs Allocatable
A machine with 16 cores does not give your applications 16 cores. Part of it is spoken for before any pod arrives.
Where the missing room goes
Every node runs its own helper programs: the agent that talks to the cluster, the container runtime, the operating system and its logging. These need CPU and memory too. Kubernetes lets you reserve space for them and also sets safety thresholds so that the node does not collapse under pressure. What remains for your pods is called allocatable.
flowchart TB
CAP["Node capacity: everything the machine has"] --> KR["Reserved for Kubernetes helpers"]
CAP --> SR["Reserved for the operating system"]
CAP --> EV["Eviction safety margin"]
CAP --> ALLOC["Allocatable: what pods can request"]
ALLOC --> DS["Per-node helper pods such as logging and monitoring agents"]
ALLOC --> APPS["Your application pods"]
The pieces explained
- Kubernetes reserved: room kept for the node agent and the container runtime.
- System reserved: room kept for the operating system itself.
- Eviction thresholds: when free memory or disk falls below a set level, the node starts removing pods to protect itself. Typical defaults include keeping at least about 100 mebibytes of memory free and some percentage of disk free. This slice is also subtracted from what you can allocate.
The exact defaults vary by Kubernetes version and by cloud provider, and managed services often set their own reservations that grow with machine size. You can read the real numbers from each node’s status, which lists capacity and allocatable side by side.
The small-machine tax
Reservations do not shrink in proportion to the machine. A tiny node loses a larger percentage to overhead than a big one. On a very small machine, the fixed costs of the operating system and node agent might eat a quarter or more of the memory. On a large machine the same costs are a small share. This is one reason very small nodes can be wasteful.
An apartment building has hallways, stairwells and a boiler room. A tiny building loses a big part of its floor space to these shared areas, while a large tower loses a smaller fraction. The sellable space is smaller than the total space, and the gap is the overhead.
Per-node helper pods
Some pods run once on every node, such as log collectors, monitoring agents, network components and security tools. They are called DaemonSet pods. Their requests are subtracted from the room available for your applications on each node. On a hundred nodes, a helper that asks for a quarter of a core costs twenty-five cores of your cluster. Count these costs; they grow with the number of nodes, not with the amount of traffic.
When you plan, always use allocatable minus per-node helpers as the usable room, never raw machine size. Many capacity spreadsheets are wrong by ten to twenty percent for this reason alone.
7Measuring What You Have
You cannot plan from a feeling. A plan starts with a trustworthy picture of today.
The measurements you need
Requested vs allocatable
For each node group, the total of pod requests divided by the allocatable total. This tells you how full the scheduler thinks the cluster is.
Actual use over time
CPU and memory usage per pod, per workload and per node, kept for weeks or months, not just the last hour.
Signs of strain
Pending pods, CPU throttling, evictions, out-of-memory kills, restarts and slow scheduling.
Business traffic
Requests per second, users, jobs per hour. These are the cause; resource use is the effect.
Use percentiles, not only averages
An average hides the peaks that actually cause outages. If a service uses 1 core most of the day and 4 cores for ten minutes during a rush, its average may look like 1.1 cores, but the cluster must be able to supply 4. Planning therefore looks at high percentiles, for example the ninety-fifth or ninety-ninth, and also at the absolute maximum over a long window that includes busy days.
A river that averages one metre deep can still flood a village for one afternoon each spring. Engineers who build bridges plan for the flood, not for the average. Your busiest ten minutes are your spring flood.
Look at a long enough window
One normal week may not contain the monthly report run, the end-of-quarter rush or the seasonal sale. A good rule is to look at at least one full business cycle, and preferably more, so that you see weekly rhythms and the rare peaks. Short retention in your monitoring system is a hidden capacity risk because it forces you to plan blind.
Allocation versus utilization: reading the gap
| Allocation | Utilization | What it usually means |
|---|---|---|
| High | Low | Requests are too generous. Money is wasted, and nodes appear full when they are not |
| High | High | Healthy but tight. Little room to grow; plan more capacity |
| Low | High | Dangerous. Requests are too small, so the scheduler overfills nodes and pods fight over resources |
| Low | Low | Oversized cluster. Consider shrinking |
flowchart LR
APPS["Workloads"] --> KUBELET["Node agents report usage"]
KUBELET --> COLLECT["Metrics collector"]
COLLECT --> STORE["Long-term metrics storage"]
STORE --> DASH["Dashboards and reports"]
STORE --> ALERT["Alerts"]
STORE --> MODEL["Capacity model and forecasts"]
BIZ["Business traffic data"] --> MODEL
Keep daily summaries (for example, the peak and the ninety-fifth percentile for each workload) for at least a year, even if detailed data is thrown away sooner. Small summaries answer almost every planning question and cost very little to store.
8Right-Sizing Requests
All cluster capacity maths rests on pod requests. If requests are wrong, every later number is wrong too.
Why requests are usually wrong
People set requests once, often by copying from another service or by guessing high to be safe, and then never touch them again. Studies of real clusters repeatedly show that a large share of requested CPU and memory is never used. The opposite error also exists: teams that set requests very low to fit more pods, and then suffer noisy-neighbour trouble.
A simple method
Collect usage
Gather weeks of real CPU and memory data per container, including the busiest periods.
Choose a percentile
For CPU requests, a high percentile such as the ninety-fifth is common. For memory, use the peak plus a margin, because running out is costly.
Add a margin
Add a modest cushion, for example ten to twenty percent, to absorb unseen peaks and growth.
Apply gradually
Change a few services first and watch for throttling, restarts and latency before spreading the change.
Repeat
Usage changes with every release. Make right-sizing a recurring task, not a one-off clean-up.
Tools that help
The Vertical Pod Autoscaler can watch usage and suggest better requests. It can run in a recommendation-only mode, which is a safe way to learn what it would change without it restarting any pods. Dashboards from tools such as Goldilocks present these recommendations per workload. Cost tools such as OpenCost show how much each team’s over-requesting costs in money, which is often the most persuasive evidence for people who own the workloads.
Think of booking a meeting room. If everyone books the biggest room “just in case”, the building looks fully booked while most rooms hold three people. A good office checks real attendance and nudges people to book the right size. Right-sizing is that nudge for pods.
Guard rails that prevent new waste
- LimitRange: sets default and maximum requests and limits in a namespace so that pods with no settings still get sensible ones.
- ResourceQuota: caps the total a namespace can request, so one team cannot take everything.
- Policy checks: admission rules that reject pods with no requests or with absurdly large ones.
Do not cut requests across the board in one step because a dashboard shows low average use. Short rare peaks are exactly what averages hide. Cut gradually and keep a rollback plan.
9Choosing Node Sizes and Shapes
Should you buy a few huge machines or many small ones? The answer depends on your pods, your risk and your overhead.
Big nodes
Large machines waste less on fixed overhead, fit big pods easily and reduce the number of nodes to manage. But losing one removes a large slice of the cluster at once, and rolling upgrades drain a lot of work at a time. They also hit the per-node pod limit and the per-node network limits more easily when pods are small.
Small nodes
Small machines lose a bigger percentage to overhead and may be unable to host a large pod at all. Each one is cheap to lose, and capacity can be added in fine steps. But there are more machines to patch, more per-node helper pods and a heavier load on the control plane.
Fewer, larger nodes
- Lower percentage overhead
- Large pods fit easily
- Fewer machines to manage
- Better chance to share caches and local data
Fewer, larger nodes: costs
- One failure removes a big chunk of capacity
- Coarse steps when scaling
- Pod count and network limits can bind first
- Rolling upgrades are heavier
Many, smaller nodes
- A failure is a small loss
- Fine-grained scaling
- Better spread across zones
- Gentle upgrades
Many, smaller nodes: costs
- Higher percentage overhead
- Per-node helper pods multiply
- Large pods may not fit
- More load on the control plane
Matching the CPU-to-memory ratio
Cloud machines come in families with different ratios of memory to CPU. General-purpose machines often offer around four gibibytes per core, compute-optimized ones offer around two, and memory-optimized ones offer eight or more. If your workloads request memory and CPU in a ratio that does not match your machines, one resource runs out while the other is stranded. Compute the ratio of total requested memory to total requested CPU, and pick a family close to it.
Think of packing suitcases into a car boot. Packing a few huge boxes leaves awkward gaps, while packing many small bags fills every corner but takes more time. The best choice depends on the shape of what you carry. Pods are your luggage; node size is the boot.
Bin packing and stranded capacity
The scheduler is essentially packing pods into nodes. Because pods come in different sizes, some leftover room on each node is too small for any pod you actually run. This unusable leftover is called stranded capacity. Planners handle it by applying a packing efficiency factor, such as assuming only eighty-five percent of allocatable room can truly be used. Standardizing pod sizes and choosing node sizes that are clean multiples of typical pod sizes improves packing.
flowchart TB
START["Workload profile: pod sizes and memory-to-CPU ratio"] --> RATIO["Pick a machine family with a close ratio"]
RATIO --> SIZE["Pick a size where the largest pod fits comfortably"]
SIZE --> CHECK{"Pod count, IP and volume limits still fine?"}
CHECK -->|"yes"| MIX["Consider a second node group for special workloads"]
CHECK -->|"no"| SIZE2["Adjust size or relax the limit"]
SIZE2 --> SIZE
MIX --> DONE["Node shapes chosen"]
Separate groups for special workloads
Not everything belongs on the same machine type. Memory-hungry databases, graphics-using jobs, short-lived batch work and sensitive workloads may each deserve their own group of nodes, marked with labels and taints so that only the right pods land there. Too many groups, however, split your spare room into separate puddles and increase total headroom needs. Keep the number of groups small.
A useful rule of thumb is that the largest pod should be no more than about a quarter to a half of a node’s allocatable room. Bigger than that, and packing efficiency collapses.
10Headroom: The Room You Deliberately Leave Empty
A cluster running at one hundred percent is not efficient; it is fragile. Headroom is the price of resilience.
Why headroom exists
Several things need spare room at the same moment you least expect them.
Losing nodes or zones
If a machine or an entire data centre zone disappears, its pods must move somewhere. Without spare room they stay pending.
Rolling updates
During a deployment, extra new pods start before the old ones stop. This temporarily increases demand.
Draining nodes
Upgrades and patching take nodes out of service one at a time or in batches.
Sudden load
Autoscalers need minutes to add machines. Headroom covers the gap.
The N+1 idea
N+1 means having enough capacity for the normal load plus one extra unit that can fail. For nodes, you size the cluster so that the work still fits after losing the largest single node. For larger risks, you extend it to N+2, or to the loss of a whole zone.
Surviving a lost zone
Imagine a cluster spread over three zones with equal capacity. If one zone fails, only two thirds of the capacity remains. To still carry the full load, the total must be one and a half times the load. In general, with N equal zones and the need to survive the loss of one, you multiply the needed capacity by N divided by N minus one. With three zones that is 1.5; with four zones it is about 1.33; with two zones it is 2.
| Zones | Survive loss of one: multiply capacity by | Share of capacity that sits idle in normal times |
|---|---|---|
| 2 | 2.00 | 50% |
| 3 | 1.50 | 33% |
| 4 | 1.33 | 25% |
| 5 | 1.25 | 20% |
Many organizations decide that not every workload deserves full zone-loss protection. Critical customer-facing services get it; internal batch jobs do not. This is a business decision about how much insurance to buy, and capacity planners should present it as a choice with a price, not hide it as a technical detail.
An airline does not fill every seat on every plane with one big flight, and a hospital does not run every bed at full occupancy. Spare capacity is what lets them handle an emergency without turning people away. Headroom is the spare bed.
Autoscaler lag
New nodes are not instant. The autoscaler notices pending pods, asks the cloud for a machine, waits for it to boot, joins it to the cluster, pulls images and starts the pods. This can take several minutes. Your headroom must cover the traffic growth during that window. If traffic can double in two minutes and node startup takes five, the spare room in the cluster, not the autoscaler, handles the first few minutes.
flowchart LR
SPIKE["Traffic spike begins"] --> HPA["Pod autoscaler adds pods"]
HPA --> ROOM{"Free room on existing nodes?"}
ROOM -->|"yes"| FAST["Pods start in seconds"]
ROOM -->|"no"| PEND["Pods wait as Pending"]
PEND --> CA["Node autoscaler requests machines"]
CA --> BOOT["Machine boots and joins: minutes"]
BOOT --> SLOW["Pods start after minutes"]
Ways to hold headroom smartly
- Overprovisioning pods: run low-priority placeholder pods that reserve room. When real pods arrive, the placeholders are pushed out instantly and the real pods take the space, while the autoscaler quietly replaces the room.
- Percentage buffers: keep a fixed fraction, such as ten to twenty percent of allocatable room, free in each critical node group.
- Surge settings: tune rolling update speed so that deployments do not demand more room than you hold.
Headroom that is counted but never tested is imaginary. Zone-loss maths assumes that pods can really spread, that volumes can follow them and that the network supports the move. Rehearse a drain before relying on it.
11A Worked Sizing Example
Let us size a cluster step by step with simple numbers. The figures are invented for teaching, but the method is the real one.
The starting facts
Imagine an online shop whose production cluster, in the busiest week of the last quarter, showed total pod requests of 280 cores of CPU and 840 gibibytes of memory. After right-sizing, the team trusts these numbers. The business expects twenty percent growth over the next six months. The team wants to use nodes with 16 cores and 64 gibibytes, spread over three zones, and wants to survive the loss of one zone.
Step 1: usable room per node
A 16-core node does not give 16 cores to applications. After reservations and eviction margins, suppose allocatable is about 15.2 cores and 59 gibibytes. Per-node helper pods use about 1.2 cores and 3 gibibytes. That leaves roughly 14 cores and 56 gibibytes usable per node.
Step 2: apply growth
CPU: 280 × 1.2 = 336 cores. Memory: 840 × 1.2 = 1,008 gibibytes.
Step 3: divide by usable room
CPU: 336 ÷ 14 = 24 nodes. Memory: 1,008 ÷ 56 = 18 nodes. CPU needs more nodes, so CPU is the binding constraint. Memory is not the limit here.
Step 4: account for packing efficiency
Real pods do not fill nodes perfectly. Assuming eighty-five percent efficiency: 24 ÷ 0.85 = 28.2, rounded up to 29 nodes.
Step 5: protect against losing a zone
With three zones, multiply by 1.5: 29 × 1.5 = 43.5, rounded up to 44 nodes, which is roughly 15 per zone after rounding to equal groups.
| Step | Calculation | Result |
|---|---|---|
| Usable per node | Allocatable minus helper pods | 14 cores, 56 GiB |
| Future demand | 280 cores × 1.2; 840 GiB × 1.2 | 336 cores, 1,008 GiB |
| Nodes by CPU | 336 ÷ 14 | 24 |
| Nodes by memory | 1,008 ÷ 56 | 18 |
| Binding constraint | Larger of the two | CPU: 24 |
| Packing efficiency 85% | 24 ÷ 0.85 | 29 |
| Survive losing one of three zones | 29 × 1.5 | 44 |
flowchart TB
A["Peak requests: 280 cores, 840 GiB"] --> B["Add growth 20%: 336 cores, 1008 GiB"]
B --> C["Divide by usable per node: 24 by CPU, 18 by memory"]
C --> D["Take the larger: 24 nodes"]
D --> E["Packing efficiency 85%: 29 nodes"]
E --> F["Zone-loss factor 1.5: 44 nodes"]
F --> G["Check pod, IP, volume and API limits"]
Reading the answer wisely
Notice what happened: 280 cores of today’s peak turned into 44 nodes, or 704 cores of raw capacity. That is a large jump, and every multiplier is a business choice. If zone-loss protection is only needed for part of the workload, the answer drops sharply. If requests are cut by right-sizing from 280 to 220 cores, the answer drops again. The example shows why measurement quality and policy choices matter more than the arithmetic.
Final checks
- With 44 nodes, can the pod count per node and the address range still hold the expected number of pods?
- Does memory still fit after rebalancing, considering the memory-to-CPU ratio of the machines?
- Does the cloud account permit 44 machines of that type in the region, and are they available in all three zones?
- Can the control plane cope with the extra nodes and pods?
It is like planning dinner for a party. You count the guests (peak), add a few who may bring friends (growth), consider that some plates will be wasted (packing), and keep extra food in case a second table arrives (zone loss). Each addition makes sense, but together they change a small shopping list into a big one, so you decide carefully which ones you really need.
Write your assumptions on the first page of every capacity plan: growth rate, packing efficiency, headroom rule and which workloads are protected. When results surprise someone, the discussion should be about assumptions, not about arithmetic.
12Forecasting Demand
A plan is only as good as its guess about the future. Forecasting turns past patterns and business plans into numbers.
Four ingredients of a forecast
Organic growth
The steady rise in traffic or data over months. Estimated from history using simple lines or growth rates.
Seasonality
Daily, weekly and yearly cycles such as lunchtime peaks, month-end processing and holiday shopping.
Launches and campaigns
Planned moments such as a product launch or a television advert. These are known in advance if you ask the business.
Efficiency shifts
New code versions may use more or less resource per request. Migrations and new features change the shape of load.
Connecting business numbers to resources
Resource use rarely grows by itself; it follows a business driver such as orders per minute, active users or messages processed. The best forecasts first find the ratio, for example “each hundred orders per second needs about forty cores”, and then forecast the driver, which the business understands far better than engineers do. This also makes the forecast explainable to non-technical colleagues.
A helpful law from queues
A simple principle from queueing theory, often called Little’s Law, says that the number of things being worked on at once equals the arrival rate multiplied by the time each takes. For a web service: concurrent requests equal requests per second multiplied by average seconds per request. If each pod can safely handle a fixed number at once, you can estimate pods from traffic. For example, 2,000 requests per second at 0.1 seconds each means about 200 requests in flight, and if a pod handles 10 comfortably, you need roughly 20 pods at peak, before adding margin.
A café serves 30 customers an hour and each stays 20 minutes. At any moment there are about ten customers inside, so you need ten seats. Double the arrivals and you need twenty seats. The seat count follows arrivals times stay time.
Ranges, not single numbers
A single forecast number gives false confidence. Good plans offer a low, expected and high case. You then decide what to build for each: typically, you commit to buying for the expected case and ensure that the high case can be reached quickly through flexible capacity.
Lead times decide when to act
| Capacity type | Typical lead time | Planning consequence |
|---|---|---|
| Cloud machine from autoscaler | Minutes | Cover with headroom |
| Cloud quota increase | Hours to days | Request well before the peak season |
| Commitment or reservation purchase | Days, with a long contract | Decide only after reviewing stable baseline use |
| New network range or new region | Weeks | Reserve address space early; it is hard to change later |
| Own hardware | Months | Start ordering as soon as the forecast shows a shortfall |
Straight-line growth is dangerous when growth is actually accelerating. Revisit the forecast every quarter and compare it with what really happened. A forecast that is never checked cannot improve.
13Control Plane Capacity
Worker nodes are only half the story. The cluster brain has its own limits, and they surprise teams who grow quickly.
What the control plane is
The control plane is the set of programs that run the cluster: the API server that answers every question, the database called etcd that stores all objects, the scheduler that places pods, and controllers that keep reality matching the desired state. Every pod, service, secret and event is a record in that database, and every controller keeps watching it.
Documented scale guidance
Kubernetes documentation describes tested limits for a single cluster, commonly quoted as up to about 5,000 nodes, 150,000 pods, 300,000 containers and 110 pods per node. These are guidance numbers, not hard walls, and they assume reasonable object sizes and request patterns. Managed services often publish their own limits and may differ. Always check your provider’s current documentation.
What actually stresses the brain
- Object count and size: millions of small objects, or a few giant ones, slow down listing and storage.
- Database size: etcd has a storage quota, often two gibibytes by default unless raised, and when it fills the cluster stops accepting writes. Cleaning up old objects and compacting the database are routine duties.
- Request rate: many controllers and tools hitting the API server at once can overload it. Kubernetes includes a feature called API Priority and Fairness that sorts requests into queues so that important traffic is not starved by noisy clients.
- Watch pressure: every watcher holds a connection and receives every change. Tools that list everything every few seconds create heavy load.
- Churn: constant creating and deleting of pods, such as large batch jobs, loads the scheduler and database far more than a stable cluster of the same size.
flowchart LR
CLIENTS["kubectl, controllers, operators, monitoring"] --> API["API server"]
NODES["Node agents"] --> API
API --> ETCD["etcd database"]
SCHED["Scheduler"] --> API
CTRL["Controller manager"] --> API
API -->|"queues by priority"| APF["Priority and fairness"]
Picture the front desk of a large hotel. Every guest, cleaner and delivery person needs something from that one desk. Add more rooms and the desk gets busier, even if the rooms themselves are fine. The control plane is that desk.
Planning for it
Include control plane checks in every sizing exercise. Track API request latency, request rates by client, etcd size and slow-write warnings. For very large or fast-changing clusters, consider splitting into several clusters instead of growing one forever. Separate clusters per environment, per region or per large team reduce the blast radius of a mistake and keep each control plane in a comfortable range. Managed services handle much of the sizing for you, but their limits still apply.
Many large installations run many medium clusters rather than a few enormous ones. This costs more in fixed overhead and management tools, but lowers the risk that one cluster’s limits or failure affects everything.
14Network and IP Address Capacity
Network limits are quiet, hard to change and capable of stopping growth completely.
Pod addresses
Each pod gets its own IP address from a range reserved for pods. Each node is assigned a slice of that range. If the overall range is small, you cannot add more nodes or pods once it is used up, and changing it later often means rebuilding the cluster. Plan the range for the maximum expected size, not for today. A range that holds around sixty-five thousand addresses sounds large, but with a slice per node and many short-lived pods it can run out faster than expected.
Cloud limits on addresses per machine
In some cloud setups, pods get real addresses from the cloud network, and each machine type can hold only a limited number of network interfaces and addresses. That caps the pods per node regardless of CPU and memory. Small machine types can have very low ceilings. Check the numbers for each machine type you plan to use, and see whether the cluster’s network plug-in offers ways to extend them.
Other shared network limits
Connection tracking
Each node keeps a table of active connections. A busy node with a full table drops new connections silently.
DNS capacity
Every service lookup goes through the cluster DNS. Heavy traffic can overload it. Scaling DNS with the cluster size and using a node-local cache are common remedies.
NAT and egress ports
Traffic leaving the cluster often shares a few public addresses, and each has a limited number of ports. Heavy outbound connections can exhaust them.
Load balancers and ingress
Cloud load balancers have limits on count, rules and throughput. Ingress controllers need CPU and memory as traffic grows.
Network throughput
Each machine type has a bandwidth ceiling, and the links between zones and regions cost money and have limits too.
Cloud API rate limits
Creating many machines or load balancers at once can hit the provider’s request limits and delay scaling.
Think of a town’s phone numbers. If the area code only has ten thousand numbers, the town cannot grow beyond that, no matter how many houses are built. Changing the area code later disrupts everybody. IP ranges are the phone numbers of the cluster.
Overlapping address ranges between clusters or with company networks make later connections painful. Keep a central record of who owns which ranges, and reserve generous space at the start.
15Storage Capacity
Storage has two sides: the temporary space on the node and the durable volumes that outlive pods. Both can limit your cluster.
Temporary node storage
Each node uses its own disk for container images, container writable layers, logs and temporary directories. Pods can request this ephemeral storage. When disk usage crosses thresholds, the node cleans up old images and then evicts pods. Large images, verbose logs and applications that write scratch files all consume this room. Plan disk size as part of node shape, and watch for log growth.
Persistent volumes
Databases and other stateful programs keep data on volumes provided by the cloud or by a storage system. These need their own planning.
- Space: how much data now and how fast it grows. Volumes can often be expanded, but shrinking is hard.
- Speed: measured in operations per second and throughput. A volume that is large enough but too slow still causes slow applications.
- Attachment limits: each node can attach only a limited number of volumes, and the number varies by machine type. Many stateful pods can fill a node’s attachments while CPU sits idle.
- Zone ties: many cloud volumes live in one zone and can only attach to nodes in that zone. Zone-loss planning must account for this.
- Snapshots and backups: these need space and bandwidth as well, often forgotten in budgets.
Think of a kitchen. The counter is for things you are working on right now and gets cleared often; that is ephemeral storage. The pantry holds food for months; that is a persistent volume. A big pantry is no help if the kitchen has only two doors to carry things through; those are the attachment limits.
flowchart TB
NODE["Node disk"] --> IMG["Container images"]
NODE --> LOGS["Logs"]
NODE --> SCRATCH["Pod scratch space"]
POD["Stateful pod"] -->|"claims"| PVC["Volume claim"]
PVC --> PV["Persistent volume in storage system"]
PV -.->|"attach limit per node, zone tie"| NODE
A planning checklist for storage
- Total data today, monthly growth and the date the volume fills.
- Peak operations per second and throughput versus what the volume type provides.
- Maximum attachments per node versus planned stateful pods per node.
- Free disk percentage on nodes, image sizes and log rotation.
- Backup space, restore time and the capacity needed to restore in a hurry.
Alert on the rate of fill, not just the percentage. A disk at seventy percent that fills a few points per day is safer than one at fifty percent that is rising by ten points every hour.
16Sharing the Cluster: Quotas, Priority and Fair Use
When many teams share a cluster, capacity becomes a question of fairness as well as arithmetic.
Quotas
A ResourceQuota sets the total amount a namespace may request or use, such as total CPU, total memory, number of pods and number of volume claims. It prevents one team’s mistake from taking the whole cluster. Quotas are also a planning tool: the sum of all quotas shows the maximum demand the cluster might face, and comparing it to real capacity shows how much you have overcommitted.
Priority and preemption
Pods can be assigned a PriorityClass, a number that says how important they are. When the cluster is full, the scheduler can preempt, meaning remove lower-priority pods to make room for higher-priority ones. This turns a shortage into a controlled decision: batch jobs and placeholder pods give way, customer-facing services stay. Without priorities, whichever pod arrives first wins, which is rarely what the business wants.
| Tool | What it controls | Planning use |
|---|---|---|
| ResourceQuota | Total per namespace | Caps demand; shows the overcommit ratio |
| LimitRange | Default and bounds per pod or container | Stops missing or absurd requests |
| PriorityClass | Who wins in a shortage | Protects critical work; enables placeholder headroom |
| Queueing systems for batch work | When big jobs may start | Smooths peaks and avoids partial starts |
Queues for batch work
Large batch and machine-learning jobs often need many pods at once. Starting half of them and waiting for the rest wastes resources and can deadlock other jobs. Job-queueing add-ons such as Kueue admit a job only when its whole requirement fits, and share capacity between teams by agreed fair-share rules. This makes batch demand visible and plannable.
Overcommit as a choice
The total of all quotas can exceed real capacity, because teams rarely peak together. This is called overcommitment, and it is the same trick airlines use when they sell more tickets than seats. Done carefully, it raises efficiency. Done blindly, it creates the occasional day when everybody shows up and someone is turned away. Decide on an overcommit ratio deliberately and monitor how often the cluster nears full.
A shared office has a rule: each team may book up to five desks. There are fewer desks than the sum of all bookings, because teams are rarely in at once. Priority rules say whose booking survives if the office is crowded. Quotas and priorities are those rules.
Showback and chargeback
Showing each team what its workloads cost, called showback, or billing them for it, called chargeback, changes behaviour more than any reminder. When teams see that an oversized request costs real money, they start right-sizing without being asked. Cost tools can group spend by namespace, label or team to make this simple.
Put the demand forecast into the hands of the teams who own the workloads. They know about launches and migrations long before the platform team does. A short quarterly request form beats any amount of guessing.
17Cost and Purchasing Strategy
Capacity is not just a technical amount; it is something you pay for. How you buy it matters as much as how much you buy.
Three ways to pay for machines
On-demand
Pay by the hour with no commitment. Highest unit price, perfect for unpredictable or short-lived needs.
Reserved or savings plans
Promise to use a steady amount for one or more years in return for a significant discount. Best for the baseline that never goes away.
Spot or preemptible
Spare machines sold at a deep discount that the provider can take back with short notice. Excellent for fault-tolerant and batch work.
Layering the purchases
A common approach is to stack the layers. Buy commitments for the lowest level of demand that you are confident will remain all year. Use on-demand machines for the predictable daily rise above that. Use spot machines for flexible work that can handle interruption. If your baseline is 20 nodes and your daily peak is 44, you commit to something near 20, not 44.
flowchart TB
PEAK["Peak demand layer: spot and on-demand burst"] --> MID["Daily rise: on-demand and autoscaled nodes"]
MID --> BASE["Always-on baseline: committed discounts"]
Where waste hides
- Oversized requests: promised but unused room, usually the biggest source.
- Idle environments: development and test clusters running all night and weekend.
- Zombie resources: unused volumes, load balancers and snapshots that nobody owns.
- Poor packing: nodes that are half-empty because of constraints, spread rules or mismatched shapes.
- Cross-zone traffic: data transfer fees between zones that nobody noticed.
The efficiency trade-off
Squeezing out waste always works against safety margin. A cluster at ninety-five percent allocation costs less but has little room for failure. The right balance depends on what an outage costs your business. A shop that loses money every minute of downtime will happily pay for spare room. An internal reporting tool can run lean.
Think of phone plans. You buy a fixed monthly plan for the minutes you always use, and pay per minute for the occasional extra. Buying a huge plan “just in case” wastes money, and buying no plan wastes money too. Capacity purchases follow the same logic.
Never lock in long commitments for capacity you have not right-sized. You may commit to paying for the waste for years. Right-size first, then commit.
18Autoscaler Guard Rails and Cloud Limits
Autoscalers are powerful, and a plan sets their limits. Mistakes here can cost either a lot of money or an outage.
Settings that belong in your plan
- Minimum nodes: the floor, which should cover baseline load and zone spread. Too low and a sudden spike finds an empty house.
- Maximum nodes: the ceiling, which protects budget and quotas. Too low and growth stops silently.
- Allowed machine types: a short, tested list. Mixed types help find stock but complicate packing.
- Scale-down delay: how long a node must be idle before removal. Too short causes thrashing; too long wastes money.
- Pod autoscaler bounds: minimum and maximum replicas per service, tested against the cluster’s real room.
Match the two autoscalers
The pod autoscaler can ask for many more pods than the cluster can hold. The node autoscaler then adds machines, but it takes minutes. If the pod autoscaler’s maximum is higher than the node autoscaler’s maximum can support, the extra pods just sit pending. The totals must agree: the sum of every service’s maximum replicas, times its requests, must fit within the node maximum plus headroom.
Cloud account limits
Cloud accounts carry default quotas on machines per region, particular machine families, IP addresses, disks and load balancers. They differ by provider and can be raised on request, although stock of particular machine types can also run short in a zone during busy periods. Plan to request increases before they are needed, and test in all zones you rely on.
flowchart LR
HPA["Pod autoscaler max replicas"] --> NEED["Total pods x requests"]
NEED --> CAPCHK{"Fits within node autoscaler maximum?"}
CAPCHK -->|"no"| STUCK["Pods stay Pending"]
CAPCHK -->|"yes"| QUOTA{"Within cloud account quota?"}
QUOTA -->|"no"| DENIED["Scale-up request refused"]
QUOTA -->|"yes"| OK["Capacity added"]
A car with cruise control keeps its speed, but only up to the speed limit that someone set. If the limit sign is wrong, the car cruises past the right speed or stops too soon. Autoscaler bounds are those signs, and capacity planning puts them in the right places.
Alert when the node autoscaler is within about ten to twenty percent of its maximum. That alert gives you time to raise the limit before it silently stops helping.
19Validating the Plan: Testing Capacity
A plan on paper is a hypothesis. Tests turn it into knowledge.
Kinds of tests
Load tests
Send realistic, increasing traffic to the application and watch latency, errors and resource use. This reveals how much each pod can really handle.
Scale tests
Create many pods or nodes to see how the control plane, scheduler and network cope. Upstream projects offer tools such as clusterloader2 and kubemark for simulating large clusters.
Failure drills
Drain a node group or simulate losing a zone and see whether pods reschedule and whether users notice.
Scale-up timing
Measure how long it takes from a pending pod to a running one on a new node. This number sets the size of your headroom.
Soak tests
Run at high load for hours or days to find slow leaks and filling disks.
Test where it is safe, but be realistic
Testing in production gives the most realistic answer but carries risk. A staging cluster that is scaled down proportionally can teach you per-pod behaviour, but it cannot show cluster-wide limits such as control plane load or address ranges. Often teams combine both: per-service load tests in staging, and carefully controlled failure drills or traffic ramps in production during quiet periods.
Fire drills do not predict whether the building will burn, but they reveal whether the stairs are blocked and the alarm works. Capacity drills are the same: they reveal the hidden blocked stairs in your plan while the building is still empty.
What to record
- Requests per second a single pod handles within the target latency.
- Resource use per unit of business traffic.
- Time to add nodes and start pods.
- The point at which each limit is first hit, and what failed first.
These numbers feed straight back into the sizing model, closing the loop.
Synthetic load that does not look like real traffic gives false comfort. Use realistic data sizes, mix of operations and user behaviour, including the expensive requests that happen rarely.
20Monitoring, Alerting and Troubleshooting
Plans decay. Monitoring tells you when reality has drifted away from the assumptions.
Metrics to watch
| Signal | Why it matters | Typical alert idea |
|---|---|---|
| Requested share of allocatable CPU and memory | Shows when the scheduler will run out of room | Warn when headroom falls below your target |
| Pending pods and how long they wait | Direct sign of a shortage | Alert when pods wait longer than the node start time |
| CPU throttling ratio | Shows limits that are too tight | Alert on sustained throttling in key services |
| Memory kills and evictions | Signs of undersized memory or overcommit | Alert on any repeating pattern |
| Pods per node versus limit | Reveals the hidden pod ceiling | Warn near ninety percent |
| Free pod addresses | Shows the network ceiling approaching | Warn at a generous remaining margin |
| Disk fill rate and attachments | Predicts storage trouble | Alert on time-to-full, not only percentage |
| API server latency, request rate, etcd size | Shows control plane stress | Alert on rising latency and size growth |
| Autoscaler distance from its maximum | Warns before growth is blocked | Warn within ten to twenty percent |
| Cost per unit of business traffic | Shows efficiency drift | Report monthly |
A troubleshooting path for pending pods
flowchart TB
START["Pod stuck in Pending"] --> EV["Read the pod events"]
EV --> Q1{"Insufficient CPU or memory?"}
Q1 -->|"yes"| A1["Check requests and node group size; check autoscaler and its limits"]
Q1 -->|"no"| Q2{"Node selector, taints or affinity mismatch?"}
Q2 -->|"yes"| A2["Fix rules or add matching nodes"]
Q2 -->|"no"| Q3{"Volume cannot attach or zone mismatch?"}
Q3 -->|"yes"| A3["Check attachment limits and zones"]
Q3 -->|"no"| Q4{"Quota exceeded?"}
Q4 -->|"yes"| A4["Raise the quota or reduce demand"]
Q4 -->|"no"| A5["Check IP availability and scheduler health"]
Regular reviews
Hold a short capacity review every month or quarter. Compare forecast and actual, review top consumers, check headroom and limits, list upcoming business events and decide on any purchases or limit increases. A review that ends with named owners and dates is what turns monitoring into planning.
The text in a pending pod’s events is the best first clue. It typically says how many nodes were rejected and for which reason, such as insufficient memory or an unmatched label. Read it before changing anything.
21Failure Scenarios and Resource-Exhaustion Security
Running out of capacity is a reliability problem, and it can also be a security problem. Attackers and accidents use the same weaknesses.
What happens when each limit is hit
| Limit reached | What you see | Typical cure |
|---|---|---|
| Allocatable CPU or memory | Pods stay Pending | Add nodes, right-size requests, raise autoscaler maximum |
| Node memory in real use | Evictions and kills, restarts | Raise memory requests, reduce overcommit, add nodes |
| CPU limit on a container | Slow responses, throttling | Raise or remove the CPU limit, add replicas |
| Pod per node limit | Pods Pending though CPU is idle | Use larger nodes or raise the limit with care |
| IP addresses | New pods cannot get an address | Extend ranges, add secondary ranges, recycle unused pods |
| Volume attachments | Stateful pods stuck waiting | Change node types or spread stateful pods |
| etcd storage quota | Cluster refuses writes | Clean up objects, compact and defragment, raise quota |
| Cloud quota | Autoscaler cannot add machines | Request increases early |
The cascade
Capacity failures love to chain. A node is lost, pods reschedule onto the rest, those nodes run hot, more pods are evicted, retries from clients grow, and the surviving services are overwhelmed. This is called a cascading failure. Headroom, priorities and limits on retries are what stop the chain at the first or second link.
flowchart TB
LOST["A node or zone is lost"] --> MOVE["Pods reschedule onto remaining nodes"]
MOVE --> HOT{"Enough spare room?"}
HOT -->|"yes"| STABLE["Service stays healthy"]
HOT -->|"no"| PRESS["Nodes run hot, evictions begin"]
PRESS --> RETRY["Clients retry and add more load"]
RETRY --> OUT["Wider outage"]
OUT -.-> LOST
Resource exhaustion as an attack
Anyone who can create workloads, or can send traffic that triggers workloads, can try to use up your capacity. This is a denial-of-service attack from the inside or the outside. A compromised service might create thousands of pods, a malicious tenant might request all the memory, a crypto-mining program might consume spare CPU, and a flood of requests might force expensive autoscaling.
- Quotas and limit ranges cap what each team or namespace can take.
- Admission policies reject oversized or unlabelled workloads.
- Access control limits who can create pods, volumes and load balancers.
- Autoscaler maximums put a ceiling on both capacity and bill, so an attack cannot create unlimited machines.
- Rate limiting and caching at the front door keep floods from becoming internal load.
- Isolation of untrusted work on dedicated node groups keeps noisy or hostile neighbours away from critical services.
- Anomaly alerts on sudden jumps in pod count, CPU and spend reveal abuse quickly.
A water supply works for everyone as long as nobody opens every tap at once. If one house leaves all its taps running, the whole street has low pressure. Quotas are the flow limiters on each house.
An autoscaler without a maximum is a blank cheque. A bug or attack that causes endless scaling can produce a very large bill before anyone looks. Always set a ceiling and an alert for spend.
22Advantages, Disadvantages and Trade-offs
Capacity planning brings real benefits and real costs. Knowing both helps you decide how much of it your team actually needs.
Benefits of careful planning
- Fewer outages caused by running out of room
- Lower bills through right-sizing and smart purchasing
- Predictable growth with early warning on hidden limits
- Clear, evidence-based conversations with the business
- Faster, calmer response to launches and incidents
Costs and downsides
- Takes engineer time and discipline to keep up to date
- Forecasts can be wrong, and may create false confidence
- Headroom means paying for room that is usually idle
- Over-planning can slow teams down with approvals
- Tools and long-term metrics storage cost money
Key trade-offs
| Choice | Leaning one way | Leaning the other way |
|---|---|---|
| Efficiency vs resilience | High packing and little headroom saves money | Large headroom survives failures and spikes |
| Big vs small nodes | Less overhead, bigger blast radius | Smaller blast radius, more overhead |
| Tight vs generous requests | Tight requests save cost but risk contention | Generous requests are safe but wasteful |
| Commit vs stay flexible | Commitments cut price but lock you in | Flexibility costs more but adapts to change |
| One big cluster vs many | One cluster is simpler to run and share | Many clusters limit blast radius and control plane load |
| Manual vs automated sizing | Manual gives control and understanding | Automation scales but needs guard rails |
There is no universally correct point on any of these scales. The right answer depends on what an hour of downtime costs you compared with what an idle machine costs you. Write that comparison down; it makes every other decision easier.
23Design Patterns and Anti-patterns
Teams that plan well share some habits, and teams that struggle share others.
Patterns worth copying
What it looks like
Low-priority placeholder pods reserve a block of room in the cluster. When real work arrives, the placeholders are evicted at once and the real pods start immediately.
Why it helps
Real pods do not wait minutes for a new machine. The node autoscaler replaces the room in the background.
Watch for
The placeholder size must match the headroom you actually want, and it should be revisited when traffic changes.
What it looks like
Requests are reviewed on a schedule, using weeks of usage data and recommendation-only autoscaler output, and teams get a report showing what over-requesting costs them.
Why it helps
The base of all capacity maths stays honest, and owners take responsibility for their own numbers.
Watch for
Apply changes in small steps and watch throttling and restarts.
What it looks like
A short written capacity model: demand drivers, resource per unit of traffic, node shape, packing efficiency, headroom rule and limit table. It is reviewed every quarter.
Why it helps
Everyone can see the assumptions, challenge them and update them. New team members learn quickly.
Watch for
A model that nobody updates is worse than none, because it looks authoritative.
What it looks like
Layered purchasing: commitments for the steady base, on-demand machines for the daily rise and spot machines for interruption-tolerant work.
Why it helps
Costs fall without reducing the ability to respond to surprises.
Watch for
Interruption handling must be tested before relying on spot capacity.
Anti-patterns to avoid
What it looks like
Planning from average utilization on a dashboard, and ignoring requests, peaks and hidden limits.
Why it hurts
Averages hide the spikes that cause outages, while requests decide what the scheduler can place.
Better approach
Use both allocation and utilization, with high percentiles and long windows.
What it looks like
Pods deployed with no requests, or with copied values nobody has checked since the first release.
Why it hurts
The cluster looks empty on paper while nodes are overloaded, or looks full while machines are idle.
Better approach
Use default and bound policies, and review requests on a regular schedule.
What it looks like
Relying only on autoscaling, with no minimums, no headroom and no tested maximums.
Why it hurts
Scale-up takes minutes, quotas and ceilings stop it silently, and spikes arrive faster than machines.
Better approach
Define the box: floors, ceilings, headroom and quotas, and alert when you near an edge.
What it looks like
Choosing a small address range or tiny machine types to save money at the start.
Why it hurts
Address ranges and pod ceilings are hard to change later, and the cost of rebuilding exceeds the early saving.
Better approach
Reserve generous ranges, and check every per-node and per-account limit before finalizing shapes.
What it looks like
Counting zone-loss protection in the plan but never rehearsing a failure.
Why it hurts
Volumes tied to one zone, missing spread rules or full address ranges make the protection imaginary.
Better approach
Run drills in a controlled way and fix whatever they reveal.
24Best Practices and Common Mistakes
A short, practical list you can put in front of a team.
Best practices
Trust requests, then improve them
Require requests on everything, review them on a schedule, and publish cost per team.
Plan from peaks and keep long history
Use high percentiles, keep daily summaries for a year or more, and include seasonal peaks.
Use allocatable, not raw size
Subtract reservations, thresholds and per-node helpers before dividing.
Write the limit table
List pods per node, IPs, volume attachments, control plane limits, cloud quotas and their lead times.
Decide headroom as a business choice
State which workloads survive a zone loss, and price that insurance openly.
Set autoscaler floors and ceilings and alert near them
Keep pod and node autoscaler maximums consistent with each other and with cloud quotas.
Test, then trust
Load test, drain and time scale-ups. Feed results back into the model.
Review regularly
Compare forecast and actual every quarter, and write down decisions with owners and dates.
Common mistakes
- Treating node CPU and memory as the only limits.
- Believing that autoscaling removes the need for planning.
- Planning from averages and short windows.
- Using raw machine size rather than allocatable room.
- Forgetting the cost of per-node helper pods as the cluster grows.
- Counting headroom that was never tested.
- Locking in commitments before right-sizing.
- Ignoring business events until they arrive.
- Leaving quotas, priorities and defaults unset in shared clusters.
- Forgetting that address ranges and cluster-wide limits are the hardest to change.
If you can only do three things this month, do these: make sure every pod has requests, write down the headroom rule, and set an alert for pods that stay pending. These three catch a large share of capacity trouble.
25Real-World Usage and Industry Examples
The ideas here come from long experience in large-scale operations. The scenarios below are typical patterns, described in general terms.
Where the ideas came from
Kubernetes grew out of lessons from Google’s internal cluster managers, including Borg. Published papers about Borg describe the same themes you have seen here: jobs declare resource requests, the system packs them onto machines, priorities decide who yields in a shortage, and a large effort goes into reclaiming resources that were requested but not used. Capacity planning in Kubernetes is the open, everyday version of those practices.
Online retail and seasonal peaks
Retailers see enormous swings around holiday sales. A typical approach is to forecast traffic from past seasons and marketing plans, load test weeks ahead, raise cloud quotas early, pre-scale node groups before the event and keep placeholder headroom during the first minutes of the rush. After the event, they scale down and review what really happened to improve next year’s model.
Shared platforms with many teams
Internal platform teams give each team a namespace with quotas, defaults and priorities, and publish a monthly cost report. Teams that over-request see their costs, and the platform team uses the same data to decide when to buy more capacity. The conversation shifts from arguments about fairness to shared numbers.
Batch, data and machine-learning workloads
Jobs that need many pods at once, or special hardware such as graphics processors, are managed through queues with fair-share rules so that expensive machines are neither idle nor deadlocked. Spot machines handle the interruption-tolerant parts, and dedicated node groups protect the interactive services.
Very large clusters and multi-cluster designs
Organizations that push toward the documented size limits often discover that control plane latency, object counts and blast radius matter more than raw machine count. Many choose several clusters per region or per business unit, each kept comfortably below its limits, and manage them as a fleet with consistent tooling.
Cost-focused reviews
Teams that run a cost review for the first time frequently find large gaps between requested and used resources, forgotten volumes and test environments running around the clock. Fixing these usually pays for the tooling many times over, and is often the easiest way to win support for a regular planning practice.
The scenarios above are general patterns, not claims about any particular company. Your own numbers, measured in your own cluster, are always better evidence than anyone else’s story.
26Frequently Asked Questions
27Summary and Key Takeaways
What to remember
- Capacity planning balances reliability and cost. Too little causes outages, too much quietly wastes money, and both are avoidable with evidence.
- Kubernetes plans with requests. The scheduler uses promises, not usage, so accurate requests are the foundation of every capacity number.
- CPU bends and memory breaks. Throttling slows programs while memory shortages kill them, so the two need different safety margins.
- Use allocatable, not raw size. Reservations, thresholds and per-node helper pods shrink the usable room, especially on small machines.
- Headroom is deliberate insurance. Plan for lost nodes and zones, rolling updates and autoscaler lag, then test it with real drills.
- Do the maths in the open. Peak, growth, usable room, packing efficiency and zone-loss factor give a defensible answer, and the assumptions matter more than the arithmetic.
- Watch the quiet limits. Pods per node, address ranges, volume attachments, DNS, connection tracking, control plane load and cloud quotas often bind before CPU does.
- Autoscalers need a box. Set floors, ceilings and quotas, keep pod and node maximums consistent, and alert before you reach an edge.
- Share fairly and pay wisely. Quotas, priorities, queues, showback and layered purchasing keep multi-team clusters fair and cost-efficient.
- Close the loop. Measure, forecast, test and review regularly, and write down assumptions so the next review can improve them.