Day 50: Kubernetes Resource Management - CPU & Memory Limits 📊

Welcome back! 👋 Day 50 of the 100 Days Cloud DevOps Challenge, and today we're mastering Kubernetes Resource Management! This is critical for production stability - preventing resource starvation and ensuring fair resource allocation. Let's optimize! 🎯
🎯 The Mission - Pod Resource Limits
📋 TASK TICKET #DEV-8050 - Kubernetes Resource Constraints
Priority: HIGH | Type: Performance Optimization
Server: Jump Host | Cluster: Kubernetes
PROBLEM:
- Applications experiencing performance issues
- Resource constraints causing instability
- Need to enforce resource limits
REQUIREMENTS:
1. Pod Name: httpd-pod
2. Container Name: httpd-container
3. Image: httpd:latest
4. Resource Requests:
- Memory: 15Mi
- CPU: 100m
5. Resource Limits:
- Memory: 20Mi
- CPU: 100m
VERIFICATION:
- Pod running successfully
- Resources enforced
- No OOMKilled events
This is production resource optimization! ⚡
🤔 Why Resource Limits Matter?
Without Limits:
❌ Pods can consume all node resources
❌ Noisy neighbor problem
❌ Node crashes from memory pressure
❌ CPU starvation for other apps
❌ Unpredictable performance
With Limits:
✅ Fair resource allocation
✅ Predictable performance
✅ Node stability
✅ Efficient scheduling
✅ Cost optimization
Real scenario:
Without limits:
Pod A: Uses 8GB (hog!)
Pod B: Uses 100MB
Pod C: OOMKilled (not enough memory)
With limits:
Pod A: Limited to 2GB
Pod B: Guaranteed 100MB
Pod C: Runs successfully ✓
🛠️ Complete Implementation
Step 1: Access Jump Host
# SSH to jump host
ssh user@jump_host
# Verify kubectl
kubectl version --short
kubectl cluster-info
Environment ready! ✅
Step 2: Create Pod with Resource Limits
Method 1: Declarative (YAML) - Recommended
# Create pod manifest
cat > httpd-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: httpd-pod
labels:
app: httpd
spec:
containers:
- name: httpd-container
image: httpd:latest
resources:
requests:
memory: "15Mi"
cpu: "100m"
limits:
memory: "20Mi"
cpu: "100m"
ports:
- containerPort: 80
EOF
# Apply the manifest
kubectl apply -f httpd-pod.yaml
Expected output:
pod/httpd-pod created
YAML breakdown:
apiVersion: v1 # Core API
kind: Pod # Resource type
metadata:
name: httpd-pod # Pod name (required)
labels:
app: httpd # Label for selection
spec:
containers:
- name: httpd-container # Container name (required)
image: httpd:latest # Image with tag
resources: # Resource constraints
requests: # Minimum guaranteed
memory: "15Mi" # 15 Mebibytes RAM
cpu: "100m" # 100 millicores (0.1 CPU)
limits: # Maximum allowed
memory: "20Mi" # 20 Mebibytes RAM
cpu: "100m" # 100 millicores (0.1 CPU)
ports:
- containerPort: 80 # Container listens on port 80
Method 2: Imperative (kubectl run) - Quick Testing
# Create pod with dry-run to generate YAML
kubectl run httpd-pod \
--image=httpd:latest \
--dry-run=client -o yaml > httpd-pod.yaml
# Edit to add resources
# Then apply
kubectl apply -f httpd-pod.yaml
Step 3: Verify Pod Creation
# Check pod status
kubectl get pods
Expected output:
NAME READY STATUS RESTARTS AGE
httpd-pod 1/1 Running 0 30s
Detailed view:
# View with resource info
kubectl get pod httpd-pod -o wide
Expected output:
NAME READY STATUS RESTARTS AGE IP NODE
httpd-pod 1/1 Running 0 1m 10.244.1.5 node01
Step 4: Verify Resource Limits
# Describe pod to see resources
kubectl describe pod httpd-pod
Expected output (key sections):
Name: httpd-pod
Namespace: default
Priority: 0
Service Account: default
Node: node01/172.17.0.3
Start Time: Thu, 26 Dec 2024 10:00:00 +0000
Labels: app=httpd
Status: Running
IP: 10.244.1.5
Containers:
httpd-container:
Container ID: containerd://abc123...
Image: httpd:latest
Image ID: docker.io/library/httpd@sha256:def456...
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 26 Dec 2024 10:00:05 +0000
Ready: True
Restart Count: 0
Limits:
cpu: 100m
memory: 20Mi
Requests:
cpu: 100m
memory: 15Mi
Environment: <none>
Key verification points:
✅ Limits: cpu: 100m, memory: 20Mi
✅ Requests: cpu: 100m, memory: 15Mi
✅ Status: Running
✅ Ready: True
Check resource allocation:
# View pod resources in JSON format
kubectl get pod httpd-pod -o jsonpath='{.spec.containers[0].resources}'
Expected output:
{"limits":{"cpu":"100m","memory":"20Mi"},"requests":{"cpu":"100m","memory":"15Mi"}}
Step 5: Test Pod Functionality
# Check pod logs
kubectl logs httpd-pod
Expected output:
AH00558: httpd: Could not reliably determine the server's fully qualified domain name
[Thu Dec 26 10:00:05.123456 2024] [mpm_event:notice] [pid 1:tid 140] AH00489: Apache/2.4.58 (Unix) configured
[Thu Dec 26 10:00:05.123456 2024] [core:notice] [pid 1:tid 140] AH00094: Command line: 'httpd -D FOREGROUND'
Test HTTP server:
# Get pod IP
POD_IP=$(kubectl get pod httpd-pod -o jsonpath='{.status.podIP}')
# Test connectivity (from another pod or node)
kubectl run curl-test --image=curlimages/curl:latest --rm -it --restart=Never -- curl http://$POD_IP
Expected output:
<html><body><h1>It works!</h1></body></html>
Step 6: Monitor Resource Usage
# Check actual resource consumption
kubectl top pod httpd-pod
Expected output:
NAME CPU(cores) MEMORY(bytes)
httpd-pod 1m 12Mi
Analysis:
CPU: 1m (well under 100m limit)
Memory: 12Mi (within 15Mi request, under 20Mi limit)
Pod running efficiently ✅
View all pod resources:
# List all pods with resources
kubectl get pods -o custom-columns=NAME:.metadata.name,CPU_REQUEST:.spec.containers[0].resources.requests.cpu,CPU_LIMIT:.spec.containers[0].resources.limits.cpu,MEM_REQUEST:.spec.containers[0].resources.requests.memory,MEM_LIMIT:.spec.containers[0].resources.limits.memory
Expected output:
NAME CPU_REQUEST CPU_LIMIT MEM_REQUEST MEM_LIMIT
httpd-pod 100m 100m 15Mi 20Mi
Step 7: Complete Verification
# Comprehensive verification script
cat > verify.sh << 'EOF'
#!/bin/bash
echo "=== Kubernetes Resource Management Verification ==="
echo ""
echo "1. Pod Status:"
kubectl get pod httpd-pod
echo ""
echo "2. Resource Limits:"
kubectl get pod httpd-pod -o jsonpath='{.spec.containers[0].resources}' | jq
echo ""
echo "3. Current Usage:"
kubectl top pod httpd-pod
echo ""
echo "4. Pod Events:"
kubectl get events --field-selector involvedObject.name=httpd-pod --sort-by='.lastTimestamp' | tail -5
echo ""
echo "5. Container Status:"
kubectl get pod httpd-pod -o jsonpath='{.status.containerStatuses[0].state}'
echo ""
echo "✓ VERIFICATION COMPLETE"
EOF
chmod +x verify.sh
./verify.sh
Expected output:
=== Kubernetes Resource Management Verification ===
1. Pod Status:
NAME READY STATUS RESTARTS AGE
httpd-pod 1/1 Running 0 5m
2. Resource Limits:
{
"limits": {
"cpu": "100m",
"memory": "20Mi"
},
"requests": {
"cpu": "100m",
"memory": "15Mi"
}
}
3. Current Usage:
NAME CPU(cores) MEMORY(bytes)
httpd-pod 1m 12Mi
4. Pod Events:
LAST SEEN TYPE REASON OBJECT MESSAGE
5m Normal Scheduled pod/httpd-pod Successfully assigned default/httpd-pod to node01
5m Normal Pulling pod/httpd-pod Pulling image "httpd:latest"
5m Normal Pulled pod/httpd-pod Successfully pulled image "httpd:latest"
5m Normal Created pod/httpd-pod Created container httpd-container
5m Normal Started pod/httpd-pod Started container httpd-container
5. Container Status:
{"running":{"startedAt":"2024-12-26T10:00:05Z"}}
✓ VERIFICATION COMPLETE
All checks passed! 🎉
🔍 Understanding Resource Management
Requests vs Limits
Requests (Minimum Guaranteed):
CPU: 100m (0.1 core)
- Scheduler ensures node has this available
- Pod won't be scheduled on nodes without it
- Used for scheduling decisions
Memory: 15Mi
- Guaranteed to pod
- Pod won't be evicted if using this amount
- Minimum required for application
Limits (Maximum Allowed):
CPU: 100m (0.1 core)
- Pod throttled if exceeding this
- Can't use more than limit
- Prevents resource hogging
Memory: 20Mi
- Pod killed (OOMKilled) if exceeding this
- Hard cap on memory usage
- Protects node from memory exhaustion
Resource behavior:
Scenario 1: Normal operation
Usage: 12Mi RAM, 50m CPU
✓ Within both request and limit
✓ Pod runs normally
Scenario 2: High CPU usage
Usage: 15Mi RAM, 150m CPU (exceeds limit)
✓ Memory OK
✗ CPU throttled to 100m (limit enforced)
Scenario 3: Memory spike
Usage: 25Mi RAM (exceeds limit), 80m CPU
✗ Pod OOMKilled and restarted
✓ CPU OK
Scenario 4: Low resources
Usage: 10Mi RAM, 30m CPU
✓ Using less than request (efficient!)
✓ Pod runs normally
CPU Units Explained
Millicore (m) notation:
1000m = 1 CPU core
100m = 0.1 CPU core (10%)
500m = 0.5 CPU core (50%)
1500m = 1.5 CPU cores
Examples:
100m = Small workload (web server)
500m = Medium workload (API service)
1000m = Large workload (database)
2000m = Heavy workload (ML training)
CPU is compressible:
Can be throttled without killing pod
Pod slows down but keeps running
Shares CPU time with other pods
Memory Units Explained
Memory notation:
Ki = Kibibyte (1024 bytes)
Mi = Mebibyte (1024 Ki)
Gi = Gibibyte (1024 Mi)
15Mi = 15 × 1024 × 1024 = 15,728,640 bytes
20Mi = 20 × 1024 × 1024 = 20,971,520 bytes
Common sizes:
10Mi = Very small (sidecar)
100Mi = Small (simple app)
500Mi = Medium (web app)
2Gi = Large (database)
Memory is NOT compressible:
Can't be throttled
Exceeding limit = OOMKilled
Pod restarted automatically
Critical to set correctly!
QoS Classes
Kubernetes assigns QoS based on resources:
1. Guaranteed (Highest priority):
# Requests = Limits for ALL resources
requests:
memory: "20Mi"
cpu: "100m"
limits:
memory: "20Mi"
cpu: "100m"
2. Burstable (Medium priority):
# Requests < Limits (Our case!)
requests:
memory: "15Mi"
cpu: "100m"
limits:
memory: "20Mi"
cpu: "100m"
3. BestEffort (Lowest priority):
# No requests or limits set
# First to be evicted under pressure
Check QoS class:
kubectl get pod httpd-pod -o jsonpath='{.status.qosClass}'
Expected output:
Burstable
Eviction order under pressure:
1. BestEffort pods (first to go)
2. Burstable pods exceeding requests
3. Burstable pods within requests
4. Guaranteed pods (last resort)
💡 Key Takeaways
✨ Requests guarantee minimum resources
✨ Limits cap maximum usage
✨ CPU is compressible (throttled)
✨ Memory is NOT compressible (OOMKilled)
✨ 100m = 0.1 CPU core
✨ Mi = Mebibytes (1024-based)
✨ QoS classes determine eviction priority
✨ Resource management prevents noisy neighbors
🎓 Quick Interview Questions
Q: What happens if a pod exceeds CPU limits? A: CPU is throttled to the limit. Pod continues running but slows down. This is called CPU throttling or CPU pressure.
Q: What happens if a pod exceeds memory limits? A: Pod is immediately killed (OOMKilled) and restarted. Memory is incompressible, so exceeding limits causes termination.
Q: Why set requests lower than limits? A: Allows burst capacity. Pod guaranteed minimum (request) but can use more (up to limit) when available. Efficient resource utilization.
Q: What's the difference between 100m CPU and 0.1 CPU? A: They're identical. 100m = 100 millicores = 0.1 core. Just different notation, same value.
Q: How do you choose appropriate resource limits? A: Monitor actual usage with kubectl top, add 20-30% buffer for spikes, test under load, adjust based on performance metrics.
🚀 Common Resource Scenarios
Scenario 1: High Memory Application (Database)
apiVersion: v1
kind: Pod
metadata:
name: postgres-pod
spec:
containers:
- name: postgres
image: postgres:15
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
Scenario 2: CPU-Intensive Application (Video Encoding)
apiVersion: v1
kind: Pod
metadata:
name: encoder-pod
spec:
containers:
- name: encoder
image: ffmpeg:latest
resources:
requests:
memory: "512Mi"
cpu: "2000m"
limits:
memory: "1Gi"
cpu: "4000m"
Scenario 3: Minimal Sidecar Container
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
containers:
- name: main-app
image: myapp:latest
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1000m"
- name: logging-sidecar
image: fluentd:latest
resources:
requests:
memory: "50Mi"
cpu: "50m"
limits:
memory: "100Mi"
cpu: "100m"
Scenario 4: Guaranteed QoS (Critical Service)
apiVersion: v1
kind: Pod
metadata:
name: critical-api
spec:
containers:
- name: api
image: api:latest
resources:
requests:
memory: "1Gi"
cpu: "1000m"
limits:
memory: "1Gi" # Same as requests
cpu: "1000m" # Same as requests
🌟 kubectl Resource Commands
View resources:
kubectl top nodes # Node resource usage
kubectl top pods # All pods usage
kubectl top pod httpd-pod # Specific pod usage
kubectl describe node node01 # Node capacity/allocatable
Set resources:
# For deployments
kubectl set resources deployment nginx --requests=cpu=100m,memory=256Mi --limits=cpu=200m,memory=512Mi
# Edit existing pod (must delete and recreate)
kubectl delete pod httpd-pod
kubectl apply -f httpd-pod.yaml
View resource allocation:
# See all pod resources
kubectl get pods -o custom-columns=NAME:.metadata.name,MEMORY_REQUEST:.spec.containers[*].resources.requests.memory,MEMORY_LIMIT:.spec.containers[*].resources.limits.memory
# Node resource pressure
kubectl describe nodes | grep -A 5 "Allocated resources"
🔧 Troubleshooting
Issue 1: Pod OOMKilled
# Check events
kubectl describe pod httpd-pod | grep -A 10 "Events"
# Solution: Increase memory limits
# Edit YAML: limits.memory: "40Mi"
kubectl delete pod httpd-pod
kubectl apply -f httpd-pod.yaml
Issue 2: Pod Pending (Insufficient Resources)
# Check why pending
kubectl describe pod httpd-pod
# Look for: "Insufficient cpu" or "Insufficient memory"
# Solution: Reduce requests or add nodes
# Reduce: requests.cpu: "50m"
Issue 3: CPU Throttling
# Check metrics
kubectl top pod httpd-pod
# If CPU at limit constantly
# Solution: Increase CPU limits
# limits.cpu: "200m"
Issue 4: Can't Update Pod Resources
# Error: "field is immutable"
# Solution: Delete and recreate
kubectl delete pod httpd-pod
kubectl apply -f httpd-pod.yaml
# Or use Deployments (support rolling updates)
📊 Resource Planning Best Practices
1. Start Conservative:
# Begin with minimal resources
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
2. Monitor and Adjust:
# Watch for 1 week
kubectl top pod httpd-pod --watch
# Adjust to peak + 30% buffer
3. Use Limits:
# Always set limits (prevent runaway)
limits:
memory: "512Mi" # Hard cap
cpu: "500m" # Throttle at this
4. Match Requests to Limits for Critical Apps:
# Guaranteed QoS for production
requests:
memory: "1Gi"
cpu: "1000m"
limits:
memory: "1Gi" # Same = Guaranteed
cpu: "1000m"
5. Use ResourceQuota:
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-quota
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
🎉 Final Thoughts
You've successfully mastered Kubernetes resource management! This is critical for production stability and cost optimization.
What you accomplished: ✅ Created pod with resource constraints
✅ Set CPU and memory limits
✅ Understood requests vs limits
✅ Learned QoS classes
✅ Mastered resource troubleshooting
Real-world impact:
Prevent outages (no resource starvation)
Cost optimization (right-sized resources)
Fair allocation (no noisy neighbors)
Predictable performance (guaranteed resources)
Cluster stability (protected nodes)
Skills acquired:
Resource limit configuration
CPU/Memory unit conversion
QoS class understanding
Resource monitoring
Troubleshooting techniques
This is production-grade Kubernetes! 💪
Day: 50/100
Challenge: KodeKloud Cloud DevOps
Date: December 25, 2025
Topic: Kubernetes Resource Management
How do you size resources for your applications? Share your resource management strategies! 📊




