Skip to main content
RunBook Academy

KubernetesXIII · Kubernetes QoS ClassesKubernetes QoS classes

QoS classes overview — Guaranteed, Burstable, BestEffort

Advanced⏱ ~16 minkubectl

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

Not yet marked complete on this device.

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:

ClassRule
GuaranteedFor every container: requests == limits for both CPU and memory
BurstableAt least one container has requests or limits set, but not all match
BestEffortNo 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 resources field (no requests, no limits).
  • Guaranteed: every container has both requests and limits set 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:

  1. Eviction order under node pressure: BestEffort first, Burstable second, Guaranteed last.
  2. OOM behaviour: OOMKilled processes are killed in QoS order; BestEffort dies first.
  3. 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-Resources covers cgroup OOM behaviour; QoS is the cluster-level equivalent.
  • The Ansible course part XXXV-Ansible-Scripting covers service priority; QoS is the cluster-level equivalent.
  • The Observability course part LXXXVII-Kubernetes-MetricsServer covers kubectl top; use it to verify QoS assumptions.

Quiz

Knowledge check · 4 questions

  1. Q1. Which of the following Pods has the Guaranteed QoS class?

  2. Q2. Under node memory pressure, the kubelet evicts Pods in this order: Guaranteed first, Burstable second, BestEffort last.

  3. 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.

  4. 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.qosClass shows the cluster’s QoS distribution.