Turn raw node CPU and memory into allocatable capacity after system-reserved, kube-reserved and the eviction threshold.
Capacity is what the hardware has; allocatable is what the scheduler may hand out. OpenShift subtracts system-reserved, kube-reserved and the hard eviction threshold in that order, and the scheduler then packs pods against their resource requests — not their limits or their actual usage. The 250-pod per-node ceiling applies on top of the arithmetic. Reservations typically remove 8-12% of a node before a single pod schedules, so sizing a cluster from raw vCPU and RAM totals overstates real capacity and produces a cluster that cannot schedule the last deployment.
OpenShift Node Capacity
allocatable CPU = node vCPU × 1000 − system-reserved − kube-reserved; allocatable memory = node RAM − system-reserved − kube-reserved − eviction threshold; pods per node = min(allocatable ÷ request, 250).
allocatable CPU = node vCPU × 1000 − system-reserved − kube-reserved; allocatable memory = node RAM − system-reserved − kube-reserved − eviction threshold; pods per node = min(allocatable ÷ request, 250). Capacity is what the hardware has; allocatable is what the scheduler may hand out. OpenShift subtracts system-reserved, kube-reserved and the hard eviction threshold in that order, and the scheduler then packs pods against their resource requests — not their limits or their actual usage. The 250-pod per-node ceiling applies on top of the arithmetic.
Reservations typically remove 8-12% of a node before a single pod schedules, so sizing a cluster from raw vCPU and RAM totals overstates real capacity and produces a cluster that cannot schedule the last deployment.
This calculator takes 10 inputs: Worker nodes, vCPUs per node, Memory per node, system-reserved CPU, kube-reserved CPU, system-reserved memory, kube-reserved memory, Hard eviction threshold, CPU request per pod, Memory request per pod. The pre-filled defaults are a realistic starting point — replace them with figures from your own environment for a result you can act on.
Requests are a guaranteed reservation and are what the scheduler subtracts from allocatable; limits are only enforced at runtime by the cgroup. A pod with a 250m request and a 2-core limit occupies 250m of scheduling capacity, which is exactly how a node ends up oversubscribed at runtime while appearing to have room.