In this episode, we'll discuss Kubernetes computational resources management. We'll learn why we should always specify CPU and memory requests and limits, how resource allocation works, and best practices for resource management.

Note
If you want to read the previous episode, you can click the Episode 28 thumbnail below
In the previous episode, we learned about Kubernetes Dashboard for managing clusters through a web interface. In episode 29, we'll discuss Computational Resources, specifically CPU and memory management - one of the most critical aspects of running production workloads in Kubernetes.
Note: Here I'll be using a Kubernetes Cluster installed through K3s.
Understanding resource requests and limits is essential for cluster stability, efficient resource utilization, and preventing one application from starving others. Without proper resource management, your cluster can become unstable, unpredictable, and expensive.
Computational Resources in Kubernetes refer to CPU and memory that containers can consume. Kubernetes allows you to specify how much of these resources a container needs (requests) and the maximum it can use (limits).
Think of resources like a restaurant reservation - requests are your guaranteed table (minimum resources), while limits are the maximum number of people you can bring (maximum resources). The restaurant (node) needs to know both to manage seating effectively.
Key resource types:
Understanding the difference is crucial.
Requests define the minimum amount of resources guaranteed to a container.
Limits define the maximum amount of resources a container can use.
resources:
requests:
memory: "256Mi" # Guaranteed minimum
cpu: "250m" # Guaranteed minimum
limits:
memory: "512Mi" # Maximum allowed
cpu: "500m" # Maximum allowedRules:
Let's understand why resource specification is critical.
Without requests:
# Bad: No resource requests
spec:
containers:
- name: app
image: myapp:latest
# No resources specifiedIssues:
With requests:
# Good: Clear resource requests
spec:
containers:
- name: app
image: myapp:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"Benefits:
Without limits:
# Bad: No resource limits
spec:
containers:
- name: memory-leak-app
image: leaky:latest
# No limits - can consume all node memoryIssues:
With limits:
# Good: Resource limits protect node
spec:
containers:
- name: memory-leak-app
image: leaky:latest
resources:
limits:
memory: "512Mi"
cpu: "500m"Benefits:
Without proper resources:
With proper resources:
Kubernetes assigns QoS classes based on resources:
Guaranteed (highest priority):
Burstable (medium priority):
BestEffort (lowest priority):
Without resource specifications, Pods get BestEffort QoS - the worst class.
CPU is measured in cores or millicores.
# 1 CPU core
cpu: "1"
cpu: "1000m" # Same as 1 core
# Half CPU core
cpu: "0.5"
cpu: "500m" # Same as 0.5 core
# Quarter CPU core
cpu: "0.25"
cpu: "250m" # Same as 0.25 core
# 100 millicores (0.1 core)
cpu: "100m"CPU is compressible:
Example:
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
cpu: "250m" # Guaranteed 0.25 core
limits:
cpu: "500m" # Max 0.5 coreBehavior:
When container exceeds CPU limit:
# Check CPU throttling
kubectl top pod cpu-demo
# View detailed metrics
kubectl describe pod cpu-demoThrottled containers show:
Memory is measured in bytes with standard units.
# Bytes
memory: "134217728" # 128 MiB in bytes
# Kibibytes (1024 bytes)
memory: "131072Ki" # 128 MiB
# Mebibytes (1024 KiB)
memory: "128Mi" # 128 MiB
# Gibibytes (1024 MiB)
memory: "1Gi" # 1 GiB
# Decimal units (less common)
memory: "128M" # 128 MB (1000-based)
memory: "1G" # 1 GB (1000-based)Note
Use binary units (Ki, Mi, Gi) for consistency with how operating systems report memory.
Memory is incompressible:
Example:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
memory: "256Mi" # Guaranteed 256 MiB
limits:
memory: "512Mi" # Max 512 MiBBehavior:
When container exceeds memory limit:
# Check Pod status
kubectl get pod memory-demo
# Output shows OOMKilled
NAME READY STATUS RESTARTS AGE
memory-demo 0/1 OOMKilled 3 2m
# View events
kubectl describe pod memory-demo
# Events show:
# Reason: OOMKilled
# Message: Container exceeded memory limitapiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
env:
- name: POSTGRES_PASSWORD
value: "secretpassword"apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
spec:
replicas: 5
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: myworker:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
# Main application
- name: api
image: myapi:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
# Sidecar (logging agent)
- name: log-agent
image: fluent/fluentd:v1.16
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"Kubernetes assigns QoS classes automatically based on resource specifications.
Requirements:
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "256Mi" # Same as requests
cpu: "250m" # Same as requestsCharacteristics:
Requirements:
apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi" # Higher than requests
cpu: "200m" # Higher than requestsCharacteristics:
Requirements:
apiVersion: v1
kind: Pod
metadata:
name: besteffort-pod
spec:
containers:
- name: app
image: nginx:1.25
# No resources specifiedCharacteristics:
Warning
Warning: Avoid BestEffort QoS in production. Always specify at least requests for predictable behavior.
kubectl get pod guaranteed-pod -o jsonpath="{.status.qosClass}"
# Output: Guaranteed
kubectl get pod burstable-pod -o jsonpath="{.status.qosClass}"
# Output: Burstable
kubectl get pod besteffort-pod -o jsonpath="{.status.qosClass}"
# Output: BestEffortLimit total resources in a namespace.
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: development
spec:
hard:
requests.cpu: "10" # Total CPU requests
requests.memory: "20Gi" # Total memory requests
limits.cpu: "20" # Total CPU limits
limits.memory: "40Gi" # Total memory limits
pods: "50" # Max number of PodsApply quota:
kubectl apply -f resource-quota.ymlCheck quota usage:
kubectl describe resourcequota compute-quota -n developmentOutput:
Name: compute-quota
Namespace: development
Resource Used Hard
-------- ---- ----
limits.cpu 5 20
limits.memory 10Gi 40Gi
pods 15 50
requests.cpu 2.5 10
requests.memory 5Gi 20GiWhen quota is exceeded:
kubectl apply -f deployment.yml -n development
# Error: exceeded quota
Error from server (Forbidden): error when creating "deployment.yml":
pods "app-xyz" is forbidden: exceeded quota: compute-quota,
requested: requests.memory=1Gi, used: requests.memory=19.5Gi,
limited: requests.memory=20GiSet default and min/max resources for containers.
apiVersion: v1
kind: LimitRange
metadata:
name: resource-limits
namespace: development
spec:
limits:
# Container limits
- type: Container
default:
memory: "512Mi" # Default limit
cpu: "500m"
defaultRequest:
memory: "256Mi" # Default request
cpu: "250m"
max:
memory: "2Gi" # Maximum limit
cpu: "2000m"
min:
memory: "64Mi" # Minimum request
cpu: "50m"
# Pod limits
- type: Pod
max:
memory: "4Gi"
cpu: "4000m"Apply limit range:
kubectl apply -f limit-range.ymlWithout resources specified:
# Pod definition without resources
spec:
containers:
- name: app
image: nginx:1.25
# No resources specifiedKubernetes applies defaults:
# Automatically applied by LimitRange
spec:
containers:
- name: app
image: nginx:1.25
resources:
requests:
memory: "256Mi" # From defaultRequest
cpu: "250m"
limits:
memory: "512Mi" # From default
cpu: "500m"View node resources:
kubectl top nodesOutput:
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node-1 850m 42% 3.2Gi 40%
node-2 1200m 60% 4.5Gi 56%View Pod resources:
kubectl top podsOutput:
NAME CPU(cores) MEMORY(bytes)
web-app-abc123-xyz 150m 180Mi
database-def456-uvw 450m 850Mi
worker-ghi789-rst 200m 320MiView Pod resources in namespace:
kubectl top pods -n productionMetrics Server must be installed:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlVerify Metrics Server:
kubectl get deployment metrics-server -n kube-systemCheck node allocatable resources:
kubectl describe node node-1Output shows:
Capacity:
cpu: 4
memory: 8Gi
Allocatable:
cpu: 3800m
memory: 7.5Gi
Allocated resources:
Resource Requests Limits
-------- -------- ------
cpu 2500m (65%) 5000m (131%)
memory 4Gi (53%) 8Gi (106%)Problem: Pods without resources get BestEffort QoS.
Solution: Always specify at least requests:
resources:
requests:
memory: "256Mi"
cpu: "250m"Problem: Containers frequently OOMKilled or throttled.
Solution: Monitor actual usage and adjust:
# Monitor usage
kubectl top pod myapp
# Adjust limits based on actual usage
resources:
limits:
memory: "512Mi" # Increased from 256MiProblem: Pods can't be scheduled due to over-requesting.
Solution: Set requests based on actual minimum needs:
resources:
requests:
memory: "128Mi" # Reduced from 512Mi
cpu: "100m" # Reduced from 500mProblem: Wastes resources, prevents bursting.
Solution: Allow bursting for variable workloads:
resources:
requests:
memory: "256Mi" # Baseline
cpu: "250m"
limits:
memory: "512Mi" # Can burst 2x
cpu: "500m"Problem: Forgetting to set resources for all containers.
Solution: Specify resources for every container:
containers:
- name: app
resources:
requests:
memory: "256Mi"
cpu: "250m"
- name: sidecar
resources:
requests:
memory: "64Mi" # Don't forget sidecar
cpu: "50m"Before setting resources:
CPU:
Memory:
Use LimitRange for consistent defaults:
apiVersion: v1
kind: LimitRange
metadata:
name: defaults
spec:
limits:
- type: Container
defaultRequest:
memory: "128Mi"
cpu: "100m"
default:
memory: "256Mi"
cpu: "200m"Prevent namespace resource exhaustion:
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"Web servers:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"Databases:
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"Batch jobs:
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "2000m"Add annotations explaining resource choices:
metadata:
annotations:
resources.note: "Based on 2-week monitoring, peak usage 180Mi/150m"
spec:
containers:
- name: app
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"kubectl describe pod myapp
# Events show:
# Warning FailedScheduling pod has unbound immediate PersistentVolumeClaims
# 0/3 nodes are available: 3 Insufficient cpu.Solutions:
kubectl get pod myapp
# STATUS: OOMKilled
kubectl describe pod myapp
# Reason: OOMKilled
# Exit Code: 137Solutions:
kubectl top pod myapp
# CPU usage at or near limit
# Check throttling metrics
kubectl describe pod myappSolutions:
kubectl describe node node-1
# Conditions:
# MemoryPressure True
# DiskPressure FalseSolutions:
In episode 29, we've explored Computational Resources in Kubernetes in depth. We've learned why resource requests and limits are critical, how they affect scheduling and runtime behavior, and best practices for resource management.
Key takeaways:
Proper resource management is fundamental to running stable, efficient Kubernetes clusters. By understanding and implementing resource requests and limits, you ensure predictable application behavior, efficient resource utilization, and cluster stability.
Are you getting a clearer understanding of Computational Resources in Kubernetes? Keep your learning momentum going and look forward to the next episode!
Note
If you want to continue to the next episode, you can click the Episode 30 thumbnail below