Stage 5 · Platform
Workloads & Scheduling
Resource Management
QoS classes, limit ranges, resource quotas, and vertical pod autoscaler.
Resource Requests and Limits
Resource requests tell the scheduler how much CPU and memory a pod needs. Limits define the maximum the pod can use. Requests are guaranteed; limits are enforced. If a pod exceeds its memory limit, it is OOMKilled. If it exceeds CPU limits, it is throttled.
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
cpu: "500m" # 0.5 CPU cores guaranteed
memory: "256Mi" # 256 MiB guaranteed
limits:
cpu: "1000m" # Max 1 CPU core (throttled beyond)
memory: "512Mi" # Max 512 MiB (OOMKilled beyond)CPU is compressible — exceeding limits causes throttling (slowdown), not termination. Memory is incompressible — exceeding limits causes OOMKilled (immediate termination). Always set memory requests equal to limits for guaranteed QoS.
QoS Classes
Kubernetes assigns Quality of Service (QoS) classes based on resource requests and limits. When the node is under memory pressure, kubelet evicts pods in order: BestEffort first, then Burstable, then Guaranteed. This determines which pods survive under pressure.
| QoS Class | Requests | Limits | Eviction Priority |
|---|---|---|---|
| Guaranteed | All set, equal to limits | All set | Last (safest) |
| Burstable | At least one set | Not all equal | Middle |
| BestEffort | None set | None set | First (killed first) |
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
cpu: "1000m"
memory: "512Mi"
limits:
cpu: "1000m" # Must equal request
memory: "512Mi" # Must equal requestFor Guaranteed QoS, every container must have requests equal to limits for both CPU and memory. This gives the pod the highest survival priority under node pressure.
Pods without any resource requests or limits are BestEffort QoS. They are the first to be evicted when the node runs low on memory. Always set resource requests — even if you don't set limits, having requests gives you Burstable QoS instead of BestEffort.
Limit Ranges
Limit ranges set default and maximum resource requests/limits per namespace. They enforce that every container has resource constraints, even if the user forgets to specify them. This prevents unbounded resource consumption.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "4"
memory: "8Gi"
min:
cpu: "50m"
memory: "64Mi"
- type: Pod
max:
cpu: "8"
memory: "16Gi"When a container doesn't specify resources, the LimitRange fills in defaults. The max/min fields reject containers with resources outside the range. This acts as a safety net for development namespaces.
Resource Quotas
Resource quotas limit aggregate resource consumption per namespace. They set limits on total CPU, memory, storage, and object counts. When a quota is exceeded, the API server rejects the request. This prevents teams from consuming more than their share.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
persistentvolumeclaims: "20"
pods: "50"
services.loadbalancers: "2"
services.nodeports: "0" # No NodePorts allowed
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values: ["high", "medium"]scopeSelector lets you apply quotas to pods with specific PriorityClasses. This is useful for tiered resource allocation — production pods get a different quota than development pods in the same namespace.
Vertical Pod Autoscaler
VPA automatically adjusts pod resource requests based on usage. It has three modes: Off (recommend only), Initial (set on pod creation), and Auto (recreate pods with new requests). VPA cannot resize running pods — it must evict and recreate them.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: app-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: "100m"
memory: "128Mi"
maxAllowed:
cpu: "4"
memory: "8Gi"
controlledResources: ["cpu", "memory"]minAllowed and maxAllowed prevent VPA from setting extreme values. controlledResources limits which resources VPA adjusts. VPA works well with HPA for different metrics — VPA for memory, HPA for CPU or custom metrics.
cgroup v2 and CPU Throttling
cgroup v2 improves CPU throttling detection and response. It provides PSI (Pressure Stall Information) metrics that show actual resource pressure, not just usage percentages. This helps identify pods that are being throttled even when CPU usage looks low.
A pod using 400m of a 500m limit looks fine in metrics. But if it periodically spikes to 600m, it gets throttled — adding latency without showing high average usage. Check throttling with container_cpu_cfs_throttled_periods_total metric.
Run VPA in Off mode first to collect recommendations without changing pods. Check kubectl describe vpa app-vpa for current, recommended, and target values. Use these to manually adjust requests before enabling Auto mode.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.