Ready to get your hands dirty with Kubernetes resource management? This practical guide will walk you through simple exercises to understand how requests and limits work in real scenarios. No complex theory—just practical examples you can run right now.

📋 Prerequisites: You'll need a Kubernetes cluster (Minikube, kind, or any cloud provider). Basic kubectl knowledge is helpful but not required.

Exercise 1: Creating Your First Pod with Resources

Let's start simple. We'll create a pod that requests specific CPU and memory resources.

Step 1: Create a Basic Pod

Create a file called simple-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: simple-app
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
💡 What does this mean?
  • requests.memory: "64Mi" - Kubernetes will find a node with at least 64MB free
  • requests.cpu: "250m" - 250 millicores = 0.25 CPU cores
  • limits.memory: "128Mi" - Pod will be killed if it uses more than 128MB
  • limits.cpu: "500m" - Pod will be throttled if it tries to use more than 0.5 cores

Step 2: Deploy and Observe

# Apply the configuration
kubectl apply -f simple-pod.yaml

# Check if the pod is running
kubectl get pods

# View detailed information
kubectl describe pod simple-app

Look for the QoS Class in the output. It should say Burstable because requests ≠ limits.

Exercise 2: Understanding QoS Classes

Let's create three pods with different QoS classes to see how they behave.

Pod 1: Guaranteed QoS

apiVersion: v1
kind: Pod
metadata:
  name: guaranteed-pod
spec:
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        memory: "100Mi"
        cpu: "100m"
      limits:
        memory: "100Mi"  # Same as requests
        cpu: "100m"      # Same as requests

Pod 2: Burstable QoS

apiVersion: v1
kind: Pod
metadata:
  name: burstable-pod
spec:
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        memory: "50Mi"
        cpu: "50m"
      limits:
        memory: "200Mi"  # Higher than requests
        cpu: "200m"      # Higher than requests

Pod 3: BestEffort QoS

apiVersion: v1
kind: Pod
metadata:
  name: besteffort-pod
spec:
  containers:
  - name: app
    image: nginx:latest
    # No resources defined at all!

Deploy and Compare

# Deploy all three pods
kubectl apply -f guaranteed-pod.yaml
kubectl apply -f burstable-pod.yaml
kubectl apply -f besteffort-pod.yaml

# Check their QoS classes
kubectl describe pod guaranteed-pod | grep "QoS Class"
kubectl describe pod burstable-pod | grep "QoS Class"
kubectl describe pod besteffort-pod | grep "QoS Class"
✅ Expected Results:
  • guaranteed-pod → QoS Class: Guaranteed
  • burstable-pod → QoS Class: Burstable
  • besteffort-pod → QoS Class: BestEffort

Exercise 3: Simulating Memory Pressure

Now let's see what happens when a pod tries to use more memory than its limit.

Create a Memory-Hungry Pod

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
spec:
  containers:
  - name: memory-eater
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
⚠️ What's happening here? This pod is trying to allocate 150MB of memory, but its limit is only 100MB. Let's see what Kubernetes does!
# Deploy the pod
kubectl apply -f memory-demo.yaml

# Watch what happens (it will get OOMKilled)
kubectl get pods -w

# Check the reason for termination
kubectl describe pod memory-demo

You should see Reason: OOMKilled in the output. The pod exceeded its memory limit and was terminated by the kernel!

Exercise 4: CPU Throttling in Action

Unlike memory, CPU is a compressible resource. Let's see throttling in action.

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
spec:
  containers:
  - name: cpu-burner
    image: polinux/stress
    resources:
      requests:
        cpu: "100m"
      limits:
        cpu: "200m"
    command: ["stress"]
    args: ["--cpu", "2"]
# Deploy the pod
kubectl apply -f cpu-demo.yaml

# Monitor CPU usage
kubectl top pod cpu-demo

# Check for throttling (if metrics-server is installed)
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods/cpu-demo

The pod will try to use 2 full CPU cores, but Kubernetes will throttle it to 200m (0.2 cores).

Exercise 5: Resource Quotas for Namespaces

Let's create a namespace with resource limits to prevent resource hogging.

apiVersion: v1
kind: Namespace
metadata:
  name: limited-namespace
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: limited-namespace
spec:
  hard:
    requests.cpu: "1"
    requests.memory: "1Gi"
    limits.cpu: "2"
    limits.memory: "2Gi"
    pods: "10"
# Create the namespace and quota
kubectl apply -f resource-quota.yaml

# Try to create a pod that exceeds the quota
kubectl run big-pod --image=nginx \
  --namespace=limited-namespace \
  --requests='cpu=2,memory=2Gi' \
  --limits='cpu=2,memory=2Gi'

# This should fail! Check why:
kubectl describe resourcequota compute-quota -n limited-namespace
⚠️ Quota Exceeded! The pod requests more CPU than the namespace allows. This is how you protect your cluster from runaway resource consumption.

Key Takeaways

Always Set Requests

Requests help the scheduler find the right node. Without them, your pod might land on an overloaded node.

Use Limits Wisely

Memory limits prevent OOM situations. CPU limits prevent one pod from starving others.

Understand QoS Classes

Guaranteed pods are protected during eviction. BestEffort pods are sacrificed first.

Monitor Your Resources

Use kubectl top and metrics-server to track actual usage vs. limits.

Clean Up

Don't forget to clean up your test resources:

# Delete all test pods
kubectl delete pod simple-app guaranteed-pod burstable-pod besteffort-pod memory-demo cpu-demo

# Delete the test namespace
kubectl delete namespace limited-namespace

Next Steps

Now that you've practiced the basics, you're ready to dive deeper! Check out my other post on Kubernetes Internals to understand what's happening under the hood with the Linux kernel, OOM killer, and CFS scheduler.

🎉 Congratulations! You've completed the hands-on exercises. You now understand how to configure resource requests and limits, recognize QoS classes, and predict pod behavior under resource pressure.