Hitesh Sahu
Hitesh SahuHitesh Sahu
  1. Home
  2. ›
  3. posts
  4. ›
  5. …

  6. ›
  7. 2 9 Resource Allocation

Loading ⏳
Fetching content, this won’t take long…


💡 Did you know?

🍯 Honey never spoils — archaeologists found 3,000-year-old jars still edible.

🍪 This website uses cookies

No personal data is stored on our servers however third party tools Google Analytics cookies to measure traffic and improve your website experience. Learn more

Loading ⏳
Fetching content, this won’t take long…


💡 Did you know?

🍯 Honey never spoils — archaeologists found 3,000-year-old jars still edible.
kubernetes

    AI-AgenticAI

    AI-DeepLearning

    AI-GenAI

    AI-Infrastructure

    AI-Machine-Learning

    AI-Math

    AWS

    Azure

    Hobbies

    kubernetes
    • Kubernetes: Control Loops, Scheduling, and GPUs

    • Image Internals: From OCI Layers to a Running Container

    • Container Internals: What a Container Really Is

    • Kubernetes Pod Internals: What a Pod Really Is

    • Kubernetes API Server Internals

    • etcd Architecture Explained

    • Kubernetes Scheduler Internals

    • Kubernetes Informers & Controllers Explained

    • Kubernetes Networking: Pods, Services, Ingress, and CNI

    • Kubernetes Storage: PV, PVC, StorageClass, and CSI

    • Helm: Kubernetes Package Manager

    • Cloud Native Observability: Prometheus, Grafana, OpenTelemetry, and Tracing

    • Kubernetes Resource Allocation: Requests, Limits, QoS, and Quotas

    • GPU Scheduling in Kubernetes: Device Plugins, GPU Operator & MIG

    • NVIDIA Network Operator: InfiniBand, SR-IOV, RDMA, and Multus

    • Dynamic Resource Allocation: The Future of GPU Scheduling in Kubernetes

    • Kubernetes Performance at Scale

    • Optimizing AI Inference at Scale: The Full Stack

    • Kueue: Kubernetes-Native Job Queuing and Quota Management

    • Multi-Node Distributed Training on Kubernetes

    • Kubernetes Topology Manager: NUMA-Aware GPU Scheduling

    • NVIDIA NIM: Optimized Inference Microservices on Kubernetes

    • GPU Autoscaling on Kubernetes: KEDA, HPA, and Cluster Autoscaler

    • Fine-Tuning LLMs: LoRA, QLoRA, PEFT, and NeMo on Kubernetes

    • Flash Attention: Fast, Memory-Efficient Attention for LLMs

    • Kubernetes and Cloud Native Certification Path

    • kubernetes Index


    Management

    Programming

    Terraform

    Z_Appendix

    0-root

Cover Image for Kubernetes Resource Allocation: Requests, Limits, QoS, and Quotas
kubernetes

Kubernetes Resource Allocation: Requests, Limits, QoS, and Quotas

How Kubernetes allocates CPU and memory — requests vs limits, QoS classes, ResourceQuota, LimitRange, node allocatable capacity, GPU resources, and best practices for production workloads.

Kubernetes
Resource Management
QoS
ResourceQuota
LimitRange
GPU
← Previous

Kubernetes Pod Internals: What a Pod Really Is

Next →

Optimizing AI Inference at Scale: The Full Stack

Kubernetes does not simply "run containers" — it makes precise placement and enforcement decisions based on resource declarations. Getting these declarations right is the difference between a stable cluster and a cascade of OOMKills and evictions.


Node Allocatable Capacity

Before any pod is scheduled, each node publishes how much resource is actually available for workloads:

Node Capacity
  − kube-reserved   (kubelet, container runtime)
  − system-reserved (OS daemons, sshd, journald)
  − eviction-threshold
= Node Allocatable
kubectl describe node <node-name> | grep -A 8 Allocatable
Allocatable:
  cpu:               94
  memory:            755Gi
  nvidia.com/gpu:    8
  pods:              110

The scheduler only places pods on nodes where allocatable − Σ(existing pod requests) ≥ new pod requests.


Requests vs Limits

Every container should declare both values for each resource:

resources:
  requests:
    cpu: "500m"       # 0.5 core — scheduling currency
    memory: "256Mi"   # scheduling currency
  limits:
    cpu: "2"          # runtime cap — excess is throttled
    memory: "512Mi"   # runtime cap — exceed this → OOMKilled
Requests Limits
Used by Scheduler (placement) Kubelet (enforcement)
CPU exceed — Throttled (cgroup CFS)
Memory exceed — OOMKilled
Set too low Pod can't schedule Normal
Set too high Wastes capacity Prevents burst

CPU: Compressible

CPU is compressible — a container that exceeds its limit is throttled, not killed. The kernel's CFS scheduler enforces the quota.

# Check CPU throttling per container
kubectl exec -it <pod> -- cat /sys/fs/cgroup/cpu/cpu.stat | grep throttled

Memory: Incompressible

Memory is incompressible — a container that exceeds its limit is immediately killed by the OOM killer. The pod then restarts according to its restartPolicy.

# Check recent OOMKills
kubectl get events --field-selector reason=OOMKilling

Quality of Service (QoS) Classes

Kubernetes automatically assigns a QoS class to every pod based on its resource declarations. This class determines eviction order when a node runs out of memory.

Evicted first ──────────────────────────────────── Evicted last
BestEffort          Burstable              Guaranteed

Guaranteed

Every container in the pod has requests == limits for both CPU and memory:

resources:
  requests:
    cpu: "1"
    memory: "1Gi"
  limits:
    cpu: "1"
    memory: "1Gi"

Use for: production workloads, inference servers, databases.

Burstable

At least one container has requests < limits (or only requests set):

resources:
  requests:
    cpu: "200m"
    memory: "128Mi"
  limits:
    cpu: "2"
    memory: "1Gi"

Use for: most general workloads. Gets to burst when capacity is available, but yields under pressure.

BestEffort

No requests or limits set on any container:

# no resources block at all

Use for: throwaway batch jobs, dev scratchpads. Never for production.

# Check QoS class of a pod
kubectl get pod <pod> -o jsonpath='{.status.qosClass}'

The Scheduling Decision

When a pod is created, the scheduler runs two phases:

1. Filtering

Eliminates nodes that cannot satisfy the pod:

  • Node has enough allocatable CPU/memory for the requests
  • Node has required GPU type and count
  • Taints/tolerations match
  • Node affinity/anti-affinity satisfied
  • Topology spread constraints met

2. Scoring

Ranks the remaining nodes. Key scoring plugins:

Plugin Prefers
LeastAllocated Node with most remaining capacity
BalancedAllocation Even CPU/memory ratio
NodeResourcesFit Closest fit to request
ImageLocality Node that already has the image

The highest-scoring node wins. On a tie, the scheduler picks randomly.


Namespace-Level Controls

ResourceQuota

Caps the total resource consumption across all pods in a namespace:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: ml-team
spec:
  hard:
    requests.cpu: "32"
    requests.memory: 128Gi
    limits.cpu: "64"
    limits.memory: 256Gi
    requests.nvidia.com/gpu: "8"
    pods: "50"
    persistentvolumeclaims: "20"

When a namespace hits its quota, new pods are rejected with a clear error. Check usage:

kubectl describe resourcequota -n ml-team

LimitRange

Sets per-container defaults and bounds — automatically injects requests/limits when containers don't specify them:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: ml-team
spec:
  limits:
  - type: Container
    default:           # applied when no limits set
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:    # applied when no requests set
      cpu: "100m"
      memory: "128Mi"
    max:               # hard ceiling per container
      cpu: "8"
      memory: "16Gi"
    min:               # floor per container
      cpu: "50m"
      memory: "64Mi"
  - type: PersistentVolumeClaim
    max:
      storage: 100Gi

LimitRange + ResourceQuota together:

LimitRange   → enforces per-pod sensible defaults
ResourceQuota → enforces total namespace budget

GPU Resource Allocation

GPUs use the extended resource model. Requests must equal limits (no fractional allocation at the device level):

resources:
  requests:
    nvidia.com/gpu: "2"
  limits:
    nvidia.com/gpu: "2"   # must match requests

MIG — Multi-Instance GPU

NVIDIA MIG (A100, H100) partitions a physical GPU into isolated slices with dedicated memory and compute:

# Request a 1g.5gb MIG slice (1/7 of an A100 80GB)
resources:
  requests:
    nvidia.com/mig-1g.5gb: "1"
  limits:
    nvidia.com/mig-1g.5gb: "1"

Available MIG profiles on A100 80GB:

Profile Memory Compute
mig-1g.5gb 5GB 1/7
mig-2g.10gb 10GB 2/7
mig-3g.20gb 20GB 3/7
mig-4g.20gb 20GB 4/7
mig-7g.40gb 40GB 7/7

Time-Slicing (non-MIG)

Allows oversubscription — multiple pods share one GPU via time-slicing. No memory isolation:

# In device plugin ConfigMap
version: v1
sharing:
  timeSlicing:
    resources:
    - name: nvidia.com/gpu
      replicas: 4   # 4 pods can claim 1 "GPU" each

Vertical Pod Autoscaler (VPA)

VPA automatically adjusts requests based on observed usage — useful when you don't know the right values upfront:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"   # or "Off" to just recommend
  resourcePolicy:
    containerPolicies:
    - containerName: my-app
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 4
        memory: 8Gi
# See VPA recommendations
kubectl describe vpa my-app-vpa

Common Pitfalls

No Requests Set (BestEffort)

Pod gets evicted first under any memory pressure. Always set requests.

Requests = 0, Limit > 0

Scheduler thinks the pod needs zero resources, places it anywhere. Pod evicted as BestEffort under pressure despite having a limit.

Memory Limit Too Low

Sudden OOMKills under load. Profile first with VPA in Off mode, then set limits at p99 + 20% headroom.

CPU Limit Too Low

Causes CPU throttling even when the node has spare capacity. For latency-sensitive workloads, consider not setting a CPU limit while keeping a CPU request — this makes the pod Burstable but prevents artificial throttling.

Requests >> Actual Usage

Reserves node capacity that's never used. Run:

kubectl top pods -A --sort-by=cpu

and compare against declared requests. Use VPA recommendations to right-size.


Production Checklist

  • Set CPU and memory requests on every container
  • Set memory limits on every container (prevent runaway processes)
  • Consider omitting CPU limits for latency-sensitive workloads
  • Use Guaranteed QoS for inference servers and databases
  • Apply LimitRange to every namespace to catch containers with no declarations
  • Apply ResourceQuota to team namespaces for budget enforcement
  • Monitor throttling with container_cpu_cfs_throttled_seconds_total
  • Monitor OOMKills with container_oom_events_total

Related Posts

  • Kubernetes Scheduler Internals
  • GPU Scheduling in Kubernetes
  • GPU Autoscaling: KEDA, HPA, Cluster Autoscaler
  • Kueue: Job Queuing and Quota Management
  • Kubernetes Topology Manager
Hitesh Sahu
Written by Hitesh Sahu, a passionate developer and blogger.

Wed Jul 22 2026

Share This on

← Previous

Kubernetes Pod Internals: What a Pod Really Is

Next →

Optimizing AI Inference at Scale: The Full Stack

kubernetes/2-9-Resource-Allocation
Let's work together
+49 176-2019-2523
hiteshkrsahu@gmail.com
WhatsApp
Skype
Munich 🥨, Germany 🇩🇪, EU
Playstore
Hitesh Sahu's apps on Google Play Store
Need Help?
Let's Connect
Navigation
  Home/About
  Skills
  Work/Projects
  Lab/Experiments
  Contribution
  Awards
  Art/Sketches
  Thoughts
  Contact
Links
  Sitemap
  Legal Notice
  Privacy Policy

Made with

NextJS logo

NextJS by

hitesh Sahu

| © 2026 All rights reserved.