KubernetesXIII · Kubernetes QoS ClassesKubernetes QoS classes
QoS classes overview — Guaranteed, Burstable, BestEffort
What you'll learn
- Identify the three QoS classes and how each is determined
- Reason about why QoS matters for eviction and resource accounting
- Read the QoS class from a Pod's status
- Design workloads for the right QoS class
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
QoS (Quality of Service) classes are how Kubernetes classifies Pods for eviction and resource accounting. This lesson covers the three classes, how they are determined from requests and limits, and why QoS matters in production.
The three QoS classes
# Guaranteed: requests == limits for every container, every resource
containers:
- name: app
resources:
requests: {cpu: 500m, memory: 512Mi}
limits: {cpu: 500m, memory: 512Mi}
# Burstable: requests < limits (or only requests set, or only some containers)
containers:
- name: app
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
# BestEffort: no requests, no limits
containers:
- name: app
The classification:
| Class | Rule |
|---|---|
| Guaranteed | For every container: requests == limits for both CPU and memory |
| Burstable | At least one container has requests or limits set, but not all match |
| BestEffort | No container has any requests or limits |
The class is computed for the Pod as a whole, based on all its containers.
How QoS is determined
The Pod’s QoS class is computed at admission time:
flowchart TD
Pod[Pod with N containers] --> Check{Any container has<br/>requests or limits?}
Check -- no --> BE[BestEffort]
Check -- yes --> Match{All containers have<br/>requests == limits<br/>for all resources?}
Match -- yes --> G[Guaranteed]
Match -- no --> B[Burstable]
The detailed rules:
- BestEffort: every container has no
resourcesfield (no requests, no limits). - Guaranteed: every container has both
requestsandlimitsset for both CPU and memory, AND requests == limits for both. - Burstable: at least one container has resources set, but the conditions for Guaranteed are not met.
Special cases:
- If a container sets only
requests(no limits), it’s Burstable. - If a container sets only
limits(no requests), the requests default to the limits (so it’s effectively Guaranteed). - If a container sets
requests: {cpu: X}but no memory request, only the CPU request is checked for the match.
Why QoS matters
QoS affects three things:
- Eviction order under node pressure: BestEffort first, Burstable second, Guaranteed last.
- OOM behaviour: OOMKilled processes are killed in QoS order; BestEffort dies first.
- Resource accounting: BestEffort is not counted in ResourceQuota; Burstable and Guaranteed are.
flowchart TD
Pressure[Node pressure: memory low] --> Q{QoS?}
Q -- BestEffort --> E1[Evicted first]
Q -- Burstable --> E2[Evicted second]
Q -- Guaranteed --> E3[Evicted last]
E1 --> Capacity[Reclaim memory]
E2 --> Capacity
E3 --> Capacity
Reading QoS class
kubectl get pod web-7c8 -o jsonpath='{.status.qosClass}'
# Burstable
The QoS class is in the Pod’s status. It is computed at admission time and does not change unless the Pod is recreated with different resources.
You can also see it in kubectl describe:
Pod QoS Class: Burstable
Examples of each class
Guaranteed:
containers:
- name: app
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
- name: sidecar
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 100m
memory: 64Mi
Both containers have requests == limits. The Pod is Guaranteed.
Burstable:
containers:
- name: app
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Requests < limits. The Pod is Burstable.
Burstable (mixed):
containers:
- name: app
resources:
requests: {cpu: 500m, memory: 512Mi}
limits: {cpu: 500m, memory: 512Mi}
- name: sidecar
# no resources
The main is Guaranteed; the sidecar has no resources. The Pod is Burstable (the sidecar pulls it down).
BestEffort:
containers:
- name: app
# no resources
The Pod is BestEffort.
Design implications
The QoS class is a design choice with trade-offs:
- BestEffort: simplest, lowest overhead, but evicted first. Use for batch jobs that can tolerate interruption.
- Burstable: most common. Allows bursting; medium eviction priority. Use for most production workloads.
- Guaranteed: most predictable; evicted last. Use for stateful workloads (databases) that cannot tolerate interruption.
QoS and LimitRange
LimitRange can enforce default requests and limits. When applied, every container in the namespace gets defaults, which typically moves BestEffort Pods to Burstable or Guaranteed.
apiVersion: v1
kind: LimitRange
metadata:
name: default
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
After this LimitRange is applied, a Pod without explicit resources gets the defaults and is Burstable (requests < limits). The Pod is no longer BestEffort.
QoS and ResourceQuota
ResourceQuota counts requests and limits. BestEffort Pods do not count against quota (they have no requests).
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-prod
spec:
hard:
requests.cpu: "32"
requests.memory: 64Gi
A team that creates BestEffort Pods can bypass the quota (no resources means no count). Production discipline: pair ResourceQuota with LimitRange to prevent this.
Cross-course references
- The Linux course part
XXXVII-Linux-Resourcescovers cgroup OOM behaviour; QoS is the cluster-level equivalent. - The Ansible course part
XXXV-Ansible-Scriptingcovers service priority; QoS is the cluster-level equivalent. - The Observability course part
LXXXVII-Kubernetes-MetricsServercoverskubectl top; use it to verify QoS assumptions.
Quiz
Knowledge check · 4 questions
Q1. Which of the following Pods has the Guaranteed QoS class?
Q2. Under node memory pressure, the kubelet evicts Pods in this order: Guaranteed first, Burstable second, BestEffort last.
Q3. A Pod has a main container with `requests: {cpu: 500m, memory: 512Mi}, limits: {cpu: 500m, memory: 512Mi}` and a sidecar with no resources. What is the QoS class and why?
Pod `web-7c8` has main container with matching requests/limits (Guaranteed-eligible) and a sidecar with no resources. Cluster has 5 nodes with mixed workloads.
Q4. What QoS class should a production database have, and why?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Declare resources on every container. BestEffort Pods are evicted first; production workloads should be Burstable or Guaranteed.
- Use Guaranteed for stateful workloads. Databases, message queues, and other stateful services should have matching requests and limits.
- Use Burstable for stateless services. HTTP servers, workers — allow bursting with Burstable.
- Pair LimitRange with ResourceQuota. BestEffort bypasses quota; defaults from LimitRange prevent this.
- Audit QoS regularly.
kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,QOS:.status.qosClassshows the cluster’s QoS distribution.