KubernetesXIII · Kubernetes QoS ClassesKubernetes QoS classes
Burstable class — requests with bursting headroom
What you'll learn
- Design a Burstable Pod (requests below limits for bursting)
- Reason about the eviction risk for Burstable Pods
- Apply the right sizing pattern for Burstable workloads
- Distinguish Burstable from Guaranteed and BestEffort
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Burstable is the most common production QoS class. It allows the workload to burst above its requests while still reserving baseline resources. This lesson covers the rules, the trade-offs, and the sizing patterns.
The Burstable rule
A Pod is Burstable when:
- At least one container has resources set (requests or limits).
- The conditions for Guaranteed are not met (i.e., at least one resource has requests < limits, or not every container has resources).
The most common Burstable pattern:
containers:
- name: app
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
Other Burstable patterns:
# Only requests set (no limits)
containers:
- name: app
resources:
requests: {cpu: 100m, memory: 128Mi}
# no limits
# Only limits set (no requests) — defaults to limits, so Guaranteed
containers:
- name: app
resources:
limits: {cpu: 500m, memory: 512Mi}
# requests defaulted to limits — actually Guaranteed
# Mixed container QoS — main is Guaranteed, sidecar is Burstable
containers:
- name: main
resources:
requests: {cpu: 500m, memory: 512Mi}
limits: {cpu: 500m, memory: 512Mi}
- name: sidecar
resources:
requests: {cpu: 50m, memory: 32Mi}
limits: {cpu: 200m, memory: 64Mi}
# Pod is Burstable (the sidecar's requests < limits)
Why Burstable is the most common class
Burstable balances:
- Predictable scheduling: requests drive placement; the scheduler reserves enough capacity.
- Bursting: limits allow temporary spikes; the workload can use more resources than reserved when needed.
- Eviction tolerance: Burstable Pods are evicted before Guaranteed but after BestEffort. For most stateless workloads, this is acceptable.
flowchart LR
A[Stateless HTTP service] --> B[Burstable]
C[Database] --> D[Guaranteed]
E[Batch job] --> F[BestEffort]
B --> G[reserves baseline, allows burst]
D --> H[no bursting, evicted last]
F --> I[no reservations, evicted first]
For most production workloads (HTTP services, workers, background tasks), Burstable is the right balance.
The bursting trade-off
A Burstable Pod can use up to its limits but is throttled or OOMKilled if it exceeds them. The benefit is:
- CPU burst: under low load, the workload uses reservations; under spike, it can use up to the limit.
- Memory growth: caches and buffers can grow up to the limit before OOMKill.
The cost:
- Throttling at peak: if the workload tries to use more than the limit, it is throttled.
- Eviction under pressure: Burstable Pods are evicted before Guaranteed Pods.
For a typical HTTP service with bursty traffic:
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 1, memory: 1Gi}
The scheduler reserves 100m CPU and 128Mi memory. Under traffic spikes, the workload can burst up to 1 CPU and 1Gi memory. Under sustained node pressure, this Pod is evicted before Guaranteed Pods.
Sizing Burstable Pods
The discipline:
- Requests: typical usage. The scheduler reserves this; under-sized requests cause scheduling failures.
- Limits: peak usage plus headroom. Over-sized limits waste node capacity when many Pods burst at once.
For an HTTP service with 100m typical CPU and 500m peak:
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
For a worker with 50m typical CPU and 200m peak memory growth:
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: 200m, memory: 256Mi}
Production discipline: measure actual usage; size requests based on typical, limits based on peak.
The maxLimitRequestRatio
A common Kubernetes pattern: enforce that the limit is not too far above the request. This is done via LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: default
spec:
limits:
- type: Container
maxLimitRequestRatio:
cpu: "4"
memory: "2"
A container with requests.cpu: 100m, limits.cpu: 1000m
has ratio 10; above 4. The Pod is rejected.
The ratio prevents:
- A Pod with
requests.cpu: 10m, limits.cpu: 100(the workload reserves almost no CPU but can use 100 cores).
Production discipline: set maxLimitRequestRatio based on
the workload’s burst pattern. Web services: 4:1. Batch
jobs: 8:1 or higher.
Burstable and eviction order
Under node pressure, Burstable Pods are evicted in this order:
- The Burstable Pod with the highest usage-vs-request ratio is evicted first.
- If multiple Pods have similar ratios, the Pod with the largest absolute usage above request is evicted first.
A Pod using 7Gi memory with a 1Gi request has ratio 7; it is evicted before a Pod using 1.5Gi with a 1Gi request (ratio 1.5).
flowchart TD
Pressure[Node memory low] --> Q{Pod QoS?}
Q -- BestEffort --> E1[Evicted first]
Q -- Burstable --> E2[Sort by usage vs request]
E2 --> E2a[Highest ratio first]
Q -- Guaranteed --> E3[Evicted last]
Production patterns
HTTP API with burst:
containers:
- name: api
resources:
requests: {cpu: 200m, memory: 256Mi}
limits: {cpu: 2, memory: 1Gi}
Burst headroom: 10x CPU, 4x memory. Allows traffic spikes.
Worker with predictable burst:
containers:
- name: worker
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
Burst headroom: 5x CPU, 4x memory. Worker pulls jobs; bursts when the queue is full.
Sidecar with minimal resources:
containers:
- name: sidecar
resources:
requests: {cpu: 10m, memory: 16Mi}
limits: {cpu: 100m, memory: 64Mi}
A lightweight sidecar (e.g., a log shipper). Minimal requests; small limit.
Diagnosing Burstable issues
A Burstable Pod that is consistently throttled:
# On the node
cat $CGROUP/container-*/cpu.stat | grep throttled
# throttled_usec very high
# nr_throttled very high
The Pod is using CPU above its limit; the CFS scheduler throttles it. The fix: raise the limit (if legitimate) or reduce usage (profile, optimise).
A Burstable Pod that is OOMKilled:
cat $CGROUP/container-*/memory.events | grep oom
# oom_kill > 0
The Pod’s memory usage exceeded the limit. The fix: raise the limit (if legitimate) or fix a leak.
Cross-course references
- The Linux course part
XXXVII-Linux-Resourcescovers cgroup resource management; Burstable is the cluster-level equivalent. - The Ansible course part
XXXV-Ansible-Scriptingcovers service priority; Burstable is the cluster-level equivalent. - The Observability course part
LXXXVII-Kubernetes-MetricsServercoverskubectl top; use it to verify Burstable sizing.
Quiz
Knowledge check · 4 questions
Q1. A Pod has a single container with `requests: {cpu: 100m, memory: 128Mi}, limits: {cpu: 1, memory: 1Gi}`. What is its QoS class?
Q2. A Burstable Pod with `requests: {cpu: 100m, memory: 128Mi}, limits: {cpu: 1, memory: 1Gi}` can use up to 1 CPU and 1Gi memory.
Q3. An HTTP service is Burstable with `requests: {cpu: 100m, memory: 128Mi}, limits: {cpu: 500m, memory: 512Mi}`. Under traffic spikes, p99 latency spikes from 50ms to 500ms. Walk through the diagnosis and fix.
HTTP service with 5 replicas. Traffic spikes from 100 RPS to 1000 RPS for 30 seconds. p99 latency goes from 50ms (steady state) to 500ms (spike). Container restart count is 0. CPU usage peaks at 480m (just under the limit). Memory usage peaks at 400Mi.
Q4. What is the difference between Burstable and Guaranteed in terms of bursting capability?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Use Burstable for stateless services. Allows bursting; reasonable eviction priority.
- Size requests to typical usage. Over-sized requests waste capacity; under-sized cause scheduling failures.
- Set maxLimitRequestRatio in LimitRange. Prevents unbounded bursting.
- Monitor throttled_usec and oom_kill. The cgroup counters show whether the burst is sustainable.
- Audit Burstable vs Guaranteed regularly. A Pod that should be Guaranteed but is Burstable indicates a misconfiguration.