CKA — Resource Limits
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
MiandGi(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
minor more thanmax - Can apply to
Container,Pod, orPersistentVolumeClaimtypes
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.