Requests + limits on a container

resources:
  requests:
    cpu: "250m"      # 250 millicores = 0.25 core
    memory: "128Mi"
  limits:
    cpu: "500m"      # throttled if exceeded (NOT killed)
    memory: "256Mi"  # OOMKilled if exceeded

QoS classes

QoS ClassConditionEviction Priority
Guaranteedrequests == limits for ALL containersLast
Burstablerequests < limits, or only one setMiddle
BestEffortNo requests or limits at allFirst

Requests vs limits

RequestsLimits
PurposeScheduler minimum per containerCap max usage
If exceededPod stays Pending (no node)OOM kill (memory) / throttle (CPU)
  • Scheduler sums all container requests in Pod
  • HPA needs CPU requests: else <unknown> target

Admission enforcement

ObjectAdmission pluginEffect
ResourceQuotaResourceQuotaRejects objects exceeding namespace totals
LimitRangeLimitRangerInjects defaults; rejects out-of-range container resources
kubectl apply -f pod.yaml --dry-run=server   # test against admission without creating
kubectl describe quota <name> -n <ns>         # USED vs HARD
kubectl describe limitrange <name> -n <ns>    # defaults and constraints

ResourceQuota (namespace aggregate)

apiVersion: v1
kind: ResourceQuota
metadata:
  name: ns-quota
  namespace: dev
spec:
  hard:
    pods: "20"
    requests.cpu: "4"
    requests.memory: 4Gi
    limits.cpu: "8"
    limits.memory: 8Gi
    persistentvolumeclaims: "5"
kubectl create quota compute-quota --hard=requests.cpu=4,requests.memory=8Gi,pods=10
kubectl describe quota compute-quota

LimitRange (per-object defaults/constraints)

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
  - type: Container
    default:           # applied if container sets no limits
      cpu: 500m
      memory: 256Mi
    defaultRequest:    # applied if container sets no requests
      cpu: 100m
      memory: 128Mi
    max:               # hard ceiling
      cpu: "2"
      memory: 1Gi

QoS eviction order (memory pressure)

BestEffort → Burstable → Guaranteed

Retrieving QoS class

kubectl get pod <pod> -o jsonpath='{.status.qosClass}'

kubectl get pods -n <ns> \
  --output=custom-columns="NAME:.metadata.name,QOS:.status.qosClass"

kubectl get pods -n <ns> \
  --output=custom-columns="NAME:.metadata.name,QOS:.status.qosClass" \
  > /root/qos_status.txt

QoS quick reference

# Guaranteed: requests == limits, both resources, all containers
resources:
  requests: {cpu: 200m, memory: 200Mi}
  limits:   {cpu: 200m, memory: 200Mi}

# Burstable: limits only (requests unset = 0 ≠ limits)
resources:
  limits: {memory: 200Mi}

# BestEffort: no resources block at all

ResourceQuota: object count limits

spec:
  hard:
    pods: "10"
    services: "5"
    secrets: "20"
    configmaps: "10"
    persistentvolumeclaims: "4"
    resourcequotas: "1"        # counts itself: shows 1/1 immediately
    deployments.apps: "5"

Exam gotchas

  • If ResourceQuota is set, every Pod MUST specify requests and limits; LimitRange provides defaults to avoid this
  • Pending + PodExceedsFreeCPU: requests too high for any node
  • ResourceQuota vs LimitRange: namespace total vs per-Pod/container
  • Without requests, HPA cannot scale on CPU %
  • qosClass is read-only: controlled indirectly via resources