Requests, limits, LimitRange and ResourceQuota

What requests and limits each control, how they decide a Pod's QoS class and its fate under memory pressure, and how LimitRange and ResourceQuota put guardrails on a namespace.

Workloads · 15%40 min2 tasks

After this lesson

  • 01You can set requests and limits in the right units and predict the QoS class Kubernetes will assign.
  • 02You can explain what happens when a container exceeds its CPU limit and when it exceeds its memory limit.
  • 03You can create a LimitRange that defaults and caps container resources and a ResourceQuota that caps a namespace, and read both with kubectl describe.

This is the limits part of the competency Configure Pod admission and scheduling (limits, node affinity, etc.). Expect at least one task that wants exact resource values on a Pod or Deployment, and one where a namespace guardrail decides whether a Pod is admitted at all. Both are quick if you know the field names and the units cold.

Requests are for the scheduler, limits are for the kernel

A request is what the scheduler reserves: a Pod fits on a node only if the sum of requests on that node stays within its allocatable capacity. Actual usage plays no part in that decision. A limit is enforced at runtime through cgroups. A container over its CPU limit is throttled and keeps running slowly. A container over its memory limit is killed by the kernel's OOM killer; the Pod shows OOMKilled with exit code 137, and the container restarts according to restartPolicy, which usually ends in CrashLoopBackOff.

WriteMeansTrap
cpu: 1One vCPU or corecpu: 0.5 is stored as 500m; both are fine
cpu: 250mA quarter of a core (milli-CPU)Precision below 1m is rejected
memory: 128Mi128 mebibytes: 128 × 1,048,576 bytes128M is 128 × 1,000,000 bytes, about 5% less
memory: 1Gi1024 Mimemory: 128m is 0.128 bytes; the m is milli
Per-container resourcesyaml
    spec:
      containers:
        - name: api
          image: nginx:1.27
          resources:
            requests:
              cpu: 100m
              memory: 64Mi
            limits:
              cpu: 250m
              memory: 128Mi
Set and inspect without opening an editorbash
kubectl -n wl-res set resources deploy/api -c api --requests=cpu=100m,memory=64Mi --limits=cpu=250m,memory=128Mi
kubectl -n wl-res get pod -l app=api -o jsonpath='{.items[0].spec.containers[0].resources}'; echo
kubectl -n wl-res get pod -l app=api -o jsonpath='{.items[0].status.qosClass}'; echo
kubectl describe node cka-worker | sed -n '/Allocated resources/,/Events/p'   # requests and limits already committed
kubectl -n wl-res top pod --containers                                         # actual usage, from metrics-server

Two defaults to remember. If a container sets a limit but no request, the request is set equal to the limit. If it sets a request but no limit, there is no limit unless a LimitRange supplies one. Changing resources on a Deployment edits the Pod template, so it triggers a rollout.

QoS classes

ClassRuleUnder node memory pressure
GuaranteedEvery container has CPU and memory limits, and its requests equal its limitsEvicted last
BurstableNot Guaranteed, but at least one container has a CPU or memory request or limitEvicted after BestEffort, those furthest over their requests first
BestEffortNo container has any request or limitEvicted first

The class is computed when the Pod is created and stored in status.qosClass. Two separate mechanisms act on it: the kernel's OOM killer, which fires when one container crosses its own memory limit, and kubelet eviction, which removes whole Pods when the node runs short. Eviction ranks Pods by whether usage exceeds requests, then by Pod priority, then by how far over they are.

LimitRange: defaults and bounds per object

Container defaults and a ceiling for one namespaceyaml
apiVersion: v1
kind: LimitRange
metadata:
  name: container-defaults
  namespace: wl-quota
spec:
  limits:
    - type: Container
      default:            # limit applied when a container sets none
        cpu: 200m
        memory: 256Mi
      defaultRequest:     # request applied when a container sets none
        cpu: 100m
        memory: 128Mi
      max:                # anything above is rejected at admission
        cpu: 500m
        memory: 512Mi
      min:
        cpu: 50m
        memory: 32Mi

The LimitRanger admission plugin applies a LimitRange when a Pod is created; running Pods are never changed. A defaulted Pod carries the annotation kubernetes.io/limit-ranger naming what was filled in. If you set max without default, the default limit becomes the max; if you set default without defaultRequest, the default request becomes the default limit. The type can also be Pod (totals across containers) or PersistentVolumeClaim (storage size). There is no kubectl create limitrange; write the YAML.

ResourceQuota: a budget for the whole namespace

Create, then read used against hardbash
kubectl -n wl-quota create quota team-quota --hard=pods=4,requests.cpu=1,requests.memory=1Gi,limits.cpu=2,limits.memory=2Gi
kubectl -n wl-quota create quota objects --hard=count/deployments.apps=3,services=5,configmaps=10,persistentvolumeclaims=2
kubectl -n wl-quota describe quota
kubectl describe ns wl-quota          # quotas and limit ranges together

Once a quota covers requests.cpu or limits.memory, every new Pod in the namespace must declare those values or be rejected with must specify limits.cpu. That is why a quota almost always comes with a LimitRange. Quota is checked at admission: lowering it never removes existing objects, it only blocks new ones.

In the docs · the tab you get on exam day

Taskwl-res-1
Workloads4%~5 min

context · kubectl config use-context kind-cka

Give a Pod exact requests and limits

In namespace wl-res create a Pod cache with one container named redis (image redis:7-alpine). The container requests 100m CPU and 64Mi memory and is limited to 250m CPU and 128Mi memory. When it is running, write the QoS class Kubernetes assigned to the Pod (the class name only) to /tmp/cka/wl-res-qos.txt.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-1/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-1/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-1/cleanup | bash
Taskwl-res-2
Workloads6%~8 min

context · kubectl config use-context kind-cka

Put defaults and a budget on a namespace

In namespace wl-quota: create a LimitRange container-defaults so that containers that specify nothing get a request of 100m CPU and 128Mi memory and a limit of 200m CPU and 256Mi memory, and no container may be limited above 500m CPU or 512Mi memory. Create a ResourceQuota team-quota allowing at most 4 Pods, 1 CPU and 1Gi memory of requests, and 2 CPU and 2Gi memory of limits. Finally create a Pod defaulted (image nginx:1.27) with no resources section; it must be running.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-2/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-2/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-res-2/cleanup | bash

Finished reading?

0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.