Kubernetes triples pod density by enabling swap on NVMe SSDs
On October 5, 2026, an official Kubernetes blog post documents node swap, generally available since v1.34, with measured gains of up to 3× density on local SSD. Enable it for best-effort workloads and AI agents, but never to mask a memory leak.
October 5, 2026. A Kubernetes blog post by Ocean Xie and Yuan Wang documents node swap, generally available since v1.34. 240 isolated pods on a single node, versus 80 without swap. 3×. That is the density gain measured on Python sandboxes. Why it matters: after years in which the kubelet refused to start with swap enabled, the platform is now officially embracing a mechanism that changes the economics of memory-oversubscribed nodes.
Why swap was forbidden
For nearly a decade, swap was off-limits in Kubernetes. The kubelet would simply refuse to start on a node where swap was mounted — failSwapOn: true was the default, and enabling swap meant explicitly overriding it. Two technical reasons justified the dogma.
The first is memory accounting. Under cgroup v1, the controller treated memory and swap as a single merged limit: there was no way to set an independent bound for disk swap. A container could therefore push a large share of its anonymous memory onto disk, making its real usage unpredictable and hard to isolate from a neighbour. The second brake was latency: paging to a slow spinning disk punished applications heavily, and the density benefit was wiped out by degraded response times.
The result: operators preferred to kill a pod cleanly with OOM rather than let it spill onto a slow, poorly accounted disk. A rational choice in the cgroup v1 plus spinning-disk world.
What changed
Both locks came off at once. cgroup v2 brings separate swap accounting: memory and disk swap are tracked independently, so you can set a distinct swap limit and know exactly what a container has paged out. And local NVMe SSDs dropped paging latency to a point where it no longer dominates the cost: page out the dormant memory, keep the active set in RAM.
The October 5 post formalizes the result. Node swap support has been GA since v1.34, and it rests on that pairing: cgroup v2 for accounting, NVMe for speed. On GKE, the mechanism is exposed natively through the Node Memory Swap feature configured on local SSD profiles.
The benchmark numbers
The post measures three workload families, quantifying the trade-off precisely.
| Workload | Baseline capacity (no swap) | Local SSD swap capacity | Density improvement |
|---|---|---|---|
| Linux CI/CD kernel build | 600 MB RAM limit | 300 MB RAM limit | −50% RAM footprint |
| Headless Chrome (Kata) | 40 pods | 50 pods | +25% |
| Headless Chrome (gVisor) | 80 pods | 160 pods | +100% |
| Python sandbox (gVisor) | 80 pods | 240 pods | +200% |
The kernel build case is the most instructive about what swap actually is. Compiling Linux 6.1.1 demands a big memory spike at link time, but leaves many compiled objects inactive in RAM the rest of the time — exactly the profile of a CI/CD pipeline. Without swap, a 600 MB limit was needed to avoid OOM. Routing swap to a local SSD cuts the limit to 300 MB, and the build finishes in 374 s versus 433 s without swap. But dropping to 200 MB forces the active working set into swap: execution time jumps by more than 40%. The lesson in one sentence — swap is insurance against spikes, not a substitute for RAM.
The agentic workloads tell the same story at greater scale. On a c4-standard-32 node (32 vCPU, 120 GB RAM), unsandboxed runc containers capped out at 512 pods; local SSD swap pushes the limit to 768. With strict security runtimes the effect is even clearer, because isolation has a memory cost: gVisor went from 80 to 160 pods, and Kata Containers from 40 to 50 microVMs. Isolated Python sandboxes — sessions analyzing 5 million rows of the MovieLens 20M dataset, with a resident footprint of about 375 MiB per execution — jumped from 80 to 240 concurrent sessions, a 3× improvement.
The telling detail: at these peak densities, the extra latency comes mainly from CPU contention between pods, not from swap I/O. An operator tuning for a specific latency target will run below the peak and see a proportionally smaller cost.
How to enable it
Enabling comes down to the kubelet configuration, dropping the historical lock and bounding the swap behaviour:
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
failSwapOn: false
memorySwap:
swapBehavior: LimitedSwap Two settings complete the mechanism. On the disk side, point swap at a fast local SSD — on GKE, enable Node Memory Swap on a local SSD profile. On the workload side, configure your workloads with Burstable QoS: set the container’s memory limit above its request. The node then automatically rations fast swap space based on idle application memory while keeping active processes responsive.
What it does not fix
Node swap is not a silver bullet, and the post says so plainly. First, it does not repair a memory leak: an application that allocates without releasing will saturate swap exactly as it would have saturated RAM, with the same eventual crash — just later and slower. Second, latency-critical workloads should stay in Guaranteed QoS: giving them a limit equal to their request excludes them from the mechanism and preserves response time. Finally, the gain assumes a fast local disk; routing swap to a slow network volume will reintroduce exactly the penalty NVMe removed.
Verdict
If you operate clusters hosting AI agents, sandboxes or CI/CD pipelines with long idle phases, enable node swap on local SSD today: the GKE numbers show up to 3× density, often with no measurable latency cost, on the same infrastructure. If your workloads are latency-critical, keep them in Guaranteed QoS and leave swap to Burstable pods — the mechanism is built to absorb spikes, not to carry your databases. If you are unsure about the principle, hold on to the post’s distinction: swap is insurance against memory spikes, never a replacement for RAM — and anyone who uses it to hide a leak will pay the bill later.