Most resource advice says to match both limits to the request on every container and call the pod Guaranteed. Follow it here and you introduce latency you never needed. The right default is narrower: cap memory at its request, leave CPU uncapped, land as Burstable. A request is what the scheduler reserves, a limit the ceiling. Treat them the same and you ignore that CPU and memory fail differently. > [!TIP] > Memory limit equal to the request, no CPU limit, Burstable. Right for most workloads. Go beyond it only when you can name why. Set a CPU and memory request on **every** container. A request-less container looks free to the scheduler, so it packs onto a full node and gets evicted under pressure, and free to the [cluster autoscaler](/docs/hetzner/apalla/clusters/configure/autoscale-a-cluster), so a pod that should trigger a scale-up silently never does. ## Why the CPU limit stays off CPU is throttled, not killed. A CPU limit is an absolute CFS quota: hit it and the kernel slows the container even when the node has idle cores, latency in exchange for nothing. The request already sets a guaranteed floor, so let the pod burst into spare CPU. Add a CPU limit only to fence a proven noisy neighbour. Memory is the opposite. It cannot be reclaimed by slowing a container down, so a container that grows past its request with no limit starves the node and gets its neighbours OOM-killed. Cap the limit at the request to hold it to what it reserved; if it needs more, raise both numbers rather than dropping the limit. ## QoS follows from your requests Kubernetes derives each pod's QoS class from its requests and limits, and that class decides who the kubelet evicts first under memory pressure: | Class | When | Under pressure | | -------------- | ------------------------------------------------------------ | ------------------------ | | **Guaranteed** | every container has requests equal to limits, CPU and memory | evicted last | | **Burstable** | at least one request set, but not Guaranteed | evicted after BestEffort | | **BestEffort** | no requests or limits at all | evicted first | That combination lands you in **Burstable**, protected on memory and free on CPU. Use **Guaranteed** only when a workload demands it, such as a [NUMA-aligned](/docs/hetzner/apalla/workloads/specialized/run-numa-aligned-workloads) database that pins cores with whole-integer CPU requests equal to limits. ## Node capacity is not the whole machine The scheduler places against a node's **allocatable** capacity, not its physical size. The platform reserves CPU and memory for system daemons, holds back an eviction buffer, and caps pods per node. See [Node resources and limits](/docs/hetzner/apalla/reference/node-resources-and-limits) for the figures. Never size a pool as if every byte were schedulable. ## Right-size from real usage Guessing requests wastes money high and triggers evictions low. Measure instead: the [Vertical Pod Autoscaler](/docs/hetzner/apalla/workloads/scaling/vertical-pod-autoscaler) recommends requests from history.