CKA — Resource Limits

6 minute read

CKA Exam Domain

Workloads & Scheduling — 15%

Manage resource limits and quotas. Understand QoS classes.

As a cluster administrator, you must ensure workloads don’t starve each other of resources. This section covers requests, limits, QoS classes, LimitRange, and ResourceQuota — all heavily tested on the CKA exam.

Requests vs Limits

Every container in a Pod can specify resource requests and resource limits:

  Requests Limits
Purpose Minimum resources guaranteed to the container Maximum resources the container can consume
Scheduler Uses requests to decide which node can run the Pod Not used by the scheduler
Enforcement Soft — container can use more if available Hard — container is throttled (CPU) or killed (memory)
Required for HPA, scheduling decisions Preventing resource abuse

YAML example

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: nginx:1.27
    resources:
      requests:
        cpu: 100m       # Guaranteed 100 millicores
        memory: 128Mi   # Guaranteed 128 MiB
      limits:
        cpu: 250m       # Max 250 millicores
        memory: 256Mi   # Max 256 MiB — OOMKilled if exceeded

Exam tip: Always set both requests and limits. Requests ensure scheduling. Limits prevent a single Pod from consuming all node resources.

CPU and Memory Units

CPU units

Value Meaning
1 1 vCPU / 1 core / 1 hyperthread
1000m Same as 1 CPU (millicores)
500m Half a CPU core
100m 0.1 CPU core
250m Quarter of a CPU core

Memory units

Value Meaning
128Mi 128 mebibytes (134,217,728 bytes)
256Mi 256 mebibytes
1Gi 1 gibibyte (1,073,741,824 bytes)
128M 128 megabytes (128,000,000 bytes) — binary vs decimal

Best practice: Use Mi and Gi (binary) for consistency with how Kubernetes reports memory.

QoS Classes

Kubernetes assigns a Quality of Service (QoS) class to every Pod based on its resource configuration. QoS classes determine which Pods get evicted first when a node runs out of resources.

QoS Class Condition Eviction Priority
Guaranteed Every container has requests == limits for both CPU and memory Evicted last (highest priority)
Burstable At least one container has requests or limits set, but they differ Evicted second
BestEffort No container has any requests or limits Evicted first (lowest priority)

Guaranteed example

resources:
  requests:
    cpu: 500m
    memory: 256Mi
  limits:
    cpu: 500m        # Same as request
    memory: 256Mi    # Same as request

Burstable example

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m        # Different from request
    memory: 512Mi    # Different from request

BestEffort example

# No resources section at all
containers:
- name: app
  image: nginx:1.27

Check QoS class:

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

What Happens When Limits Are Exceeded?

Resource Behavior When Limit Is Exceeded
CPU Container is throttled — it’s given less CPU time but keeps running
Memory Container is OOMKilled (Out of Memory Killed) — it’s terminated and may be restarted based on restartPolicy
# Check for OOMKilled
kubectl get pods
# STATUS: OOMKilled or CrashLoopBackOff

kubectl describe pod <pod-name> | grep -A3 "Last State"

Key difference: CPU is compressible (can be throttled). Memory is incompressible (must be killed).

LimitRange

A LimitRange sets default, minimum, and maximum resource constraints for individual containers in a namespace. It’s enforced at Pod admission time.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
  - type: Container
    default:          # Default limits (if none specified)
      cpu: 500m
      memory: 256Mi
    defaultRequest:   # Default requests (if none specified)
      cpu: 100m
      memory: 128Mi
    min:              # Minimum allowed
      cpu: 50m
      memory: 64Mi
    max:              # Maximum allowed
      cpu: "2"
      memory: 1Gi
  - type: Pod
    max:
      cpu: "4"
      memory: 2Gi

What LimitRange does:

  • Applies default requests and limits to containers that don’t specify them
  • Rejects Pods that request less than min or more than max
  • Can apply to Container, Pod, or PersistentVolumeClaim types

Apply and verify

kubectl apply -f limitrange.yaml
kubectl describe limitrange default-limits -n dev

ResourceQuota

A ResourceQuota sets aggregate resource limits for an entire namespace. It caps the total CPU, memory, and object counts that can be consumed.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 4Gi
    limits.cpu: "8"
    limits.memory: 8Gi
    pods: "20"
    services: "10"
    persistentvolumeclaims: "5"
    configmaps: "10"
    secrets: "10"

What ResourceQuota does:

  • Caps the total resources that all Pods in the namespace can request/use
  • Can also limit the count of objects (Pods, Services, ConfigMaps, etc.)
  • Once a quota is set, all new Pods must specify resource requests/limits (or have defaults from a LimitRange)

Apply and verify

kubectl apply -f resourcequota.yaml
kubectl describe resourcequota dev-quota -n dev

Example output:

Name:                   dev-quota
Namespace:              dev
Resource                Used   Hard
--------                ----   ----
configmaps              1      10
limits.cpu              500m   8
limits.memory           512Mi  8Gi
pods                    2      20
requests.cpu            200m   4
requests.memory         256Mi  4Gi
secrets                 1      10
services                0      10

LimitRange vs ResourceQuota

Feature LimitRange ResourceQuota
Scope Per container / per Pod Entire namespace (aggregate)
Purpose Default & constrain individual resources Cap total resources and object counts
Default values Yes — can set default requests and limits No
Min/Max Yes — per container No (only totals)
Object counts No Yes — can limit number of Pods, Services, etc.
When enforced At Pod admission At Pod admission

Best practice: Use both together. LimitRange ensures every Pod has sane defaults. ResourceQuota ensures the namespace doesn’t consume the entire cluster.

kubectl Commands

# Check resource requests and limits on a Pod
kubectl describe pod <pod> | grep -A5 "Limits\|Requests"

# Check QoS class
kubectl get pod <pod> -o jsonpath='{.status.qosClass}'

# View LimitRange
kubectl describe limitrange -n dev
kubectl get limitrange -n dev -o yaml

# View ResourceQuota
kubectl describe resourcequota -n dev
kubectl get resourcequota -n dev -o yaml

# View resource usage
kubectl top pods
kubectl top pods -n dev
kubectl top nodes

Practice Questions

Q1. Create a Pod named stress-test with requests: cpu=200m, memory=256Mi and limits: cpu=500m, memory=512Mi. What QoS class will it get?

Show Answer
apiVersion: v1
kind: Pod
metadata:
  name: stress-test
spec:
  containers:
  - name: stress
    image: nginx:1.27
    resources:
      requests:
        cpu: 200m
        memory: 256Mi
      limits:
        cpu: 500m
        memory: 512Mi

QoS class: Burstable (because requests ≠ limits).

Verify:

kubectl get pod stress-test -o jsonpath='{.status.qosClass}'

Q2. Create a LimitRange in namespace staging that sets default CPU request to 100m and default CPU limit to 500m.

Show Answer
kubectl create namespace staging
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-defaults
  namespace: staging
spec:
  limits:
  - type: Container
    defaultRequest:
      cpu: 100m
    default:
      cpu: 500m
kubectl apply -f limitrange.yaml
kubectl describe limitrange cpu-defaults -n staging

Q3. Create a ResourceQuota in namespace prod that allows a maximum of 10 Pods and total CPU limits of 4 cores.

Show Answer
kubectl create namespace prod
apiVersion: v1
kind: ResourceQuota
metadata:
  name: prod-quota
  namespace: prod
spec:
  hard:
    pods: "10"
    limits.cpu: "4"
kubectl apply -f quota.yaml
kubectl describe resourcequota prod-quota -n prod

Q4. What happens when a container exceeds its memory limit? What about CPU?

Show Answer
  • Memory limit exceeded — The container is OOMKilled (terminated). It may restart depending on the Pod’s restartPolicy.
  • CPU limit exceeded — The container is throttled. It receives less CPU time but continues running.

The key difference: CPU is compressible (can be restricted), memory is incompressible (must be terminated).


Q5. A namespace has a ResourceQuota set, but new Pods without resource requests are being rejected. Why?

Show Answer

When a ResourceQuota is active in a namespace, all new Pods must specify resource requests and limits for the resources that the quota tracks. If a Pod doesn’t specify them and there’s no LimitRange to provide defaults, the Pod is rejected.

Fix: Create a LimitRange in the namespace to provide default requests and limits.


Time to put everything together in a hands-on lab.

Next: Hands-On Lab →

Updated: