Should I enable swap on Kubernetes in production?

Choose between right-sizing, an isolated swap pilot and more RAM using workload behaviour, SLOs and a financial break-even test.

25 October 2026 · 9 min read · Cloudline Consulting

Three engineers reviewing a printed chart in an office beside a server room.
Photo: YellowstoneNPS (PDM 1.0)

Your CI runners keep hitting memory limits, browser workers leave CPU idle, and another RAM upgrade looks expensive. October’s Kubernetes benchmarks make SSD-backed swap worth investigating, but their largest density gain belongs to a particular sandbox workload—not your entire platform. The production question is whether cheaper completed work survives the latency, storage and operational costs. Start with three possible decisions: right-size requests, pilot swap in an isolated pool, or keep RAM-only nodes. Then make the winning option earn its place through a repeatable acceptance test.

In this article
  1. Which workloads should get a swap pilot?
  2. Fix requests before asking swap to increase density
  3. How many London nodes must disappear to save money?
  4. Build an isolated pool without mixing provider settings
  5. Prove useful throughput before approving more pods
  6. Make rollback a capacity plan rather than a panic command

Which workloads should get a swap pilot?

An engineer working on a laptop beside a second monitor.
Classify the workload before changing the node. Photo: Nicola since 1972 (BY 2.0)

Not cluster-wide, and not before measuring the workload. If you’re asking “should I enable swap on Kubernetes?”, start with one isolated workload, not a fleet-wide setting.

Use our Cold pages, SLO headroom, Cash framework. All three gates must pass before a Kubernetes LimitedSwap pilot earns production capacity:

  • Cold pages: measurements show anonymous memory stays allocated but is rarely accessed. High memory usage alone proves nothing.
  • SLO headroom: representative tests leave room for page-in delays within job deadlines and p99 latency objectives.
  • Cash: increased useful throughput could remove paid nodes after swap storage costs. Smaller memory limits alone do not reduce bills.
WorkloadEngineering recommendation
CI compilation and linkingPilot repeatable builds with cold pages; keep hot, memory-intensive linking in RAM.
Idle browser sessionsPilot if anonymous pages stay cold; measure resume latency.
Continuously active browser automationPrefer RAM-only when the active working set dominates.
Sandboxed Python executionPilot repeatable batch jobs; separate memory-streaming jobs.
Customer-facing APIsPrefer RAM-only where tight tail-latency objectives dominate.
DatabasesDefault to RAM-only; protect latency-sensitive working sets.
Control-plane servicesKeep RAM-only; do not make cluster recovery depend on paging.

These are engineering recommendations, not universal workload guarantees. An idle browser and a continuously busy browser are different capacity problems.

The Kubernetes post dated 5 October 2026 reports Kata Chrome concurrency increasing from 40 to 50 pods. It reports gVisor Chrome rising from 80 to 160, and gVisor Python from 80 to 240. That 3× result describes Python, not all Kubernetes workloads.

The same post supplies the practical warning: reducing the kernel-build memory limit to 200 MB increased execution time by over 40%. That is a useful boundary for Kubernetes swap performance, not evidence of equivalent billing reductions.

If any gate fails, choose right-sizing or RAM-only capacity. Start with Cloudline’s CLI guide to Kubernetes pod sizing when requests are the first problem to fix.

Swap has to earn its place in one workload, not win an argument for the whole cluster.

Share this quote

Fix requests before asking swap to increase density

Two rows of server racks in a data centre.
More backing storage does not create more schedulable RAM. Photo: D Coetzee (CC0 1.0)
kubectl top pods -A --containers
kubectl describe node "$NODE"
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,QOS:.status.qosClass,NODE:.spec.nodeName'

Start here, but do not mistake a current utilisation snapshot for a sizing history. Capture startup peaks and complete job cycles, including browser launches and concurrent CI builds. A runner idling at 500Mi can still need 4Gi during compilation.

  • Requests are scheduling inputs, not measurements of current consumption.
  • Limits are enforced memory ceilings, not reserved RAM.
  • Actual resident memory is what currently occupies physical RAM. The working-set metric from kubectl top is not an exact RSS measurement.
  • Cold anonymous pages are infrequently accessed, non-file-backed memory: potential swap candidates, not proof of spare capacity.

The scheduler places workloads using resource requests; it does not account for swap availability or consumption. Enabling swap does not increase allocatable physical memory. Over-requested pods may therefore remain Pending, even with unused swap space.

Correct inflated requests using observed demand and headroom. Cutting requests merely to force placement creates a different risk: more workloads competing for the same RAM during correlated peaks. That is overcommit, not Kubernetes memory optimisation.

Upstream Kubernetes LimitedSwap eligibility and allocation applies to Burstable pods, with exclusions including containers whose memory requests equal limits. Its proportional per-container swap allowance is:

(containerMemoryRequest / nodeTotalMemory) × totalPodsSwapAvailable

Lower requests can therefore also reduce a container’s swap allowance. Do not apply this formula uncritically to GKE node memory swap: Google documents allocation in terms of limits.

Cgroup v2 is a prerequisite; use Cloudline’s cgroup v2 go/no-go guide rather than treating migration as part of this pilot.

Draw two lanes behind the same cluster scheduler: a RAM-only service pool and an opt-in worker pool with encrypted SSD-backed swap. Monitoring observes both lanes. Explicit workload placement, using node affinity and taints with tolerations, keeps ordinary services out of the swap pool.

How many London nodes must disappear to save money?

A calculator and notebook beside an open laptop.
Calculate the whole-node break-even, including storage and machine changes. Photo: mpclemens (BY 2.0)

For 25 October 2026, model London (europe-west2) using illustrative budget inputs, not live supplier tariffs. Use 730 hours, USD, no VAT and no currency conversion. Savings require removable nodes, not a percentage extrapolated from peak pod density.

Assume existing 8-vCPU/32-GiB nodes cost $0.35/hour; swap-compatible equivalents cost $0.50/hour. Larger-memory 8-vCPU/64-GiB nodes cost $0.68/hour. Add $40/month per surviving swap node for SSD capacity.

PoolMonthly arithmeticTotal
10 existing RAM-only nodes10 × $0.35 × 730$2,555
7 compatible swap nodes7 × (($0.50 × 730) + $40)$2,835
6 compatible swap nodes6 × $405$2,430
5 or 6 larger-memory RAM-only nodes5 or 6 × ($0.68 × 730)$2,482 / $2,978.40

At least four nodes must disappear merely to cross break-even. Neither swap nor larger-memory candidate counts predict performance. Node removal must remain feasible across zones and during a node failure.

If existing machines are already compatible at $365/month, the calculation changes. Ten cost $3,650; nine swap nodes at $405 cost $3,645. That saves just $5 before additional operating costs.

The SSD allowance is a budget assumption. Google’s disk pricing documentation confirms provisioned SSD capacity is charged, including unused capacity. Local SSD pricing varies by region, machine series and disk type.

Measure total pool cost divided by unique jobs completed successfully within the agreed deadline. At an assumed 100,000 qualifying completions, $2,555 and $2,430 become $0.02555 and $0.02430 per completed job. Include retries in resource consumption, not as extra successful jobs.

Compare identical workloads, resilience headroom, boot disks, discounts, autoscaling floors and operational effort. Kubernetes swap performance matters only if useful completions survive those constraints. Extend this model to actual billing data using Cloudline’s cost-visibility breakdown.

A denser node saves nothing until you can safely stop paying for another node.

Share this quote

Build an isolated pool without mixing provider settings

An engineer standing beside an open server cabinet.
Keep experimental worker capacity separate from customer-facing services. Photo: Official GDC (BY 2.0)

Upstream Linux workers: configure kubelet, not storage

Keep the pilot isolated: label its nodes workload-pool=swap-workers and taint them swap=enabled:NoSchedule. Apply upstream settings through node-image and bootstrap management, never undocumented hand edits to managed nodes.

Kubernetes LimitedSwap requires cgroup v2, a compatible runtime and already-provisioned encrypted swap. Follow the upstream encrypted-swap provisioning tutorial. This kubelet fragment neither creates storage nor provisions encryption:

failSwapOn: false
memorySwap:
  swapBehavior: LimitedSwap

Check the node, deploy the configuration, then restart kubelet:

sudo swapon --show
stat -fc %T /sys/fs/cgroup
sudo systemctl restart kubelet

Expect cgroup2fs. Inspect the effective configuration through configz, rather than trusting the file:

kubectl get --raw "/api/v1/nodes/$NODE/proxy/configz" \
  | jq '.kubeletconfig | {failSwapOn, memorySwap}'

GKE Standard: use the provider’s pool configuration

Use an existing compatible Standard cluster running at least 1.34.1-gke.1341000. For GKE node memory swap, save this as system-config.yaml, leaving encryption enabled by default:

linuxConfig:
  swapConfig:
    enabled: true
    ephemeralLocalSsdProfile:
      swapSizePercent: 30
gcloud container node-pools create swap-workers \
  --cluster="$CLUSTER" \
  --location=europe-west2 \
  --machine-type=n2-standard-8 \
  --ephemeral-storage-local-ssd=count=1 \
  --num-nodes=1 \
  --node-locations=europe-west2-a \
  --node-labels=workload-pool=swap-workers \
  --node-taints=swap=enabled:NoSchedule \
  --system-config-from-file=system-config.yaml

This pilot shares one Local SSD with ephemeral storage; it is not a dedicated-device design. For dedicated swap, replace the profile entirely with this alternative; never combine both profiles:

linuxConfig:
  swapConfig:
    enabled: true
    dedicatedLocalSsdProfile:
      diskCount: 1

Check the pool and repeat configz inspection against one of its nodes:

gcloud container node-pools describe swap-workers \
  --cluster="$CLUSTER" --location=europe-west2

NODE=$(kubectl get nodes -l workload-pool=swap-workers \
  -o jsonpath='{.items[0].metadata.name}')
kubectl get --raw "/api/v1/nodes/$NODE/proxy/configz" \
  | jq '.kubeletconfig | {failSwapOn, memorySwap}'

Use this pod-spec fragment for a Burstable worker. Illustrative sizing: 512Mi requested, 2Gi limit, not a density recommendation.

spec:
  nodeSelector: {workload-pool: swap-workers}
  tolerations:
    - key: swap
      operator: Equal
      value: enabled
      effect: NoSchedule
  containers:
    - name: worker
      image: python:3.13-slim
      command: ["sleep", "infinity"]
      resources:
        requests:
          memory: 512Mi
        limits:
          memory: 2Gi

A toleration permits placement; the selector confines it. Terraform should own the eventual pool configuration: import an existing pool into managed infrastructure safely.

Amazon EKS managed node groups run EC2 nodes, but this GKE system-config file is not an EKS interface.

Prove useful throughput before approving more pods

An engineer examining charts on two desktop monitors.
Measure completed work and tail latency, not pod survival alone. Photo: jurvetson (BY 2.0)

Test Kubernetes swap performance with three reproducible arms:

  1. Current RAM-only configuration.
  2. Right-sized RAM-only configuration.
  3. Right-sized configuration with Kubernetes LimitedSwap.

Initially, hold application image digest, runtime isolation, CPU allocation, workload corpus and node count constant. Repeat identical workloads across all three. Then test the smaller pool required by your cost model; same-node improvements do not prove savings.

Run concurrency steps, idle-and-reactivate cycles, synchronised cold starts, sustained load and one-node-loss recovery. Measure end-to-end job completion, not just pod readiness or HTTP submission latency.

for c in 10 20 40; do
  k6 run --env CONCURRENCY="$c" --out json="results-$c.json" load.js || break
done

The accompanying load.js sets concurrency from CONCURRENCY, submits real jobs, polls completion and records a custom job_duration_ms Trend. Include failure checks for unsuccessful, incorrect or timed-out jobs. Its options include:

export const options = {
  vus: Number(__ENV.CONCURRENCY),
  duration: '30m',
  thresholds: {
    job_duration_ms: ['p(95)<60000', 'p(99)<90000'],
    checks: ['rate>0.99'],
  },
};

Substitute your actual SLOs for these example thresholds. Failed k6 thresholds produce a non-zero exit code, stopping the sweep.

The SIGs Agent Sandbox c4-standard-8 runc sweep reported 120 healthy swap-backed pods with p99 ChromeReady of 58 seconds. At 200 healthy pods, p99 reached 268 seconds. More surviving pods can still breach readiness objectives. Keep this sweep separate from the blog’s different runtime and machine comparisons.

Alongside load tests, collect node evidence:

vmstat 1
cat /proc/pressure/memory
iostat -xz 1
kubectl describe node "$NODE"
kubectl get events -A --sort-by=.lastTimestamp

Run continuous samplers in separate terminals. Correlate swap-in/out, disk latency, CPU saturation, OOMKilled events, evictions and MemoryPressure with job-duration spikes. Non-zero swap occupancy alone is not failure. On GKE, capture node and container swap-used metrics too.

Approve more pods only when SLO compliance, stable throughput, recovery and lower cost per qualifying completion hold together. These are the acceptance gates for Cloudline’s monitoring and reliability implementation, not pod-count targets.

Make rollback a capacity plan rather than a panic command

Three engineers discussing a deployment plan at a whiteboard.
Reserve fallback capacity before the pilot needs it. Photo: juhansonin (BY 2.0)

A Kubernetes swap production pilot needs an exit route with enough RAM to carry the workload. Spare SSD space is not rollback capacity. Budget for temporary overlap between pilot and fallback nodes.

For Kubernetes LimitedSwap, the sequence matters more than the command. Draining first can push swap-sized workers onto ordinary nodes and turn a contained experiment into wider memory pressure.

  1. Freeze worker concurrency. Provision sufficient RAM-only fallback capacity for the original safe worker sizing, including node-loss headroom. Wait until those nodes are Ready.
  2. Protect in-flight work. Pause new submissions, or confirm jobs can checkpoint and retry safely. Bound retries so recovery cannot flood the fallback pool.
  3. Cordon each pilot node.
    kubectl cordon "$NODE"
    Restore RAM-only placement and the original safe requests and limits in the deployment or job-controller source of truth. Apply those changes before recreating work; swap-sized workers must not spill onto ordinary nodes.
  4. Drain one node at a time.
    kubectl drain "$NODE" --ignore-daemonsets --timeout=15m
    Respect termination grace periods and PodDisruptionBudgets. If draining times out, investigate rather than bypassing eviction safeguards. Drain does not guarantee application-level job preservation. An emptyDir-related refusal requires a deliberate decision to preserve, checkpoint or discard that data—not an automatic destructive flag.
  5. Remove swap only after workloads are safe. Disable it through the managed pool configuration, or replace the pool using the RAM-only template. Do not run swapoff -a under pressure: first remove workloads and establish RAM headroom. Re-run baseline completion and SLO checks, then remove unused SSD capacity.

Acceptance and rollback checklist: these are this article’s operating policy, not upstream Kubernetes defaults.

  • Accept: workload SLOs met; no new OOM kills or evictions; no sustained memory-pressure or I/O-stall regression; successful node-loss recovery; demonstrated lower cost per completed job.
  • Roll back: sustained tail-latency breaches, falling qualifying throughput, uncontrolled retries or deteriorating node health.

For help sizing a reversible pilot, commission a Kubernetes capacity-and-reliability review.

Final thoughts

Enable swap only when cold memory, SLO headroom and the financial model agree. Right-size first, keep customer-facing services isolated, and require the smaller pool to prove useful throughput under pressure and during recovery. If those tests fail, buying RAM can be the cheaper production decision. Cloudline Consulting can help you commission a Kubernetes capacity-and-reliability review covering workload sizing, node economics, observability and a rollback plan—so the next infrastructure purchase follows evidence rather than a density headline.

Frequently asked questions

Should swap be enabled or disabled in Kubernetes?
Keep RAM-only nodes as the default for latency-sensitive services and the control plane. Consider an isolated swap pilot for workers with cold memory and enough latency tolerance. Kubernetes supports swap, but its documentation warns about noisy neighbours, unpredictable performance and storage contention. Decide using workload measurements rather than a cluster-wide rule.
What does Kubernetes LimitedSwap actually do?
LimitedSwap allows eligible workloads to use a bounded amount of node swap. Upstream Kubernetes calculates the allowance proportionally to memory requests and available pod swap. It does not offer unrestricted virtual memory, and Guaranteed or BestEffort pods cannot use it. Containers with equal memory requests and limits also opt out.
Does enabling swap let Kubernetes schedule more pods?
Not automatically. The scheduler still considers requested memory against physical node capacity and does not use swap availability for placement. Swap may help already-scheduled workloads survive memory pressure, but additional density requires appropriate requests and explicit workload placement. Lowering requests blindly can create contention rather than useful capacity.
Can GKE nodes use disk space as memory?
GKE documents node memory swap for compatible clusters from version 1.34.1-gke.1341000. Its configuration supports boot disks, shared ephemeral Local SSD storage and dedicated Local SSD storage. Swap is encrypted by default. Local SSD options require compatible machines, so include both storage and any machine-family change in the financial model.
Will Kubernetes swap reduce performance?
It can, especially when active memory repeatedly moves between RAM and storage or swap competes with other disk traffic. Fast SSDs do not remove CPU contention or guarantee acceptable tail latency. Benchmark completion times, readiness and recovery at your intended concurrency; healthy pods alone are not proof of acceptable performance.

Sources and further reading

Found this useful? Share it or cite it: