ResourceQuotas are the namespace-level spending limit. They cap the total amount of resources (CPU, memory, storage, object count) that all Pods in a namespace can collectively consume. This prevents one team from monopolizing the cluster.

1. Compute Resource Quotas

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "8"              # Total CPU requests across all Pods
    requests.memory: 16Gi          # Total memory requests
    limits.cpu: "16"               # Total CPU limits
    limits.memory: 32Gi            # Total memory limits
    pods: "20"                     # Maximum number of Pods

How It Works

# Current state:
kubectl describe quota compute-quota -n team-alpha
# Name:            compute-quota
# Resource         Used    Hard
# --------         ----    ----
# limits.cpu       6       16
# limits.memory    12Gi    32Gi
# pods             8       20
# requests.cpu     3       8
# requests.memory  8Gi     16Gi

# If a developer tries to create a Pod requesting 6 CPU (would total 9):
# → REJECTED: exceeded quota (requests.cpu: 9 > hard limit 8)
ResourceQuota enforces at creation time. When you create a Pod (or a controller creates one), the quota admission controller checks if the namespace's total would exceed the hard limit. If yes, the request is rejected. Existing Pods are NOT killed — the quota only blocks new creations.

The LimitRange Requirement

When a ResourceQuota for compute resources exists, every Pod must specify requests and limits. Otherwise the quota can't account for the Pod's usage. If a Pod doesn't specify them, it's rejected.

# Common error:
# "Error: pods "web" is forbidden: failed quota: compute-quota:
#  must specify limits.cpu, limits.memory, requests.cpu, requests.memory"

# Solution: Pair ResourceQuota with a LimitRange that provides defaults:
apiVersion: v1
kind: LimitRange
metadata:
  name: default-resources
  namespace: team-alpha
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      default:
        cpu: 500m
        memory: 256Mi
CKA exam pattern: If you create a ResourceQuota on compute resources, you almost always need a LimitRange too. Without it, Pods without explicit resource specs are rejected. The LimitRange injects defaults so existing manifests continue to work.

2. Object Count Quotas

Limit how many objects of each type can exist in a namespace:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
  namespace: team-alpha
spec:
  hard:
    pods: "20"
    services: "10"
    services.loadbalancers: "2"     # Expensive! Limit these
    services.nodeports: "5"
    secrets: "50"
    configmaps: "50"
    persistentvolumeclaims: "10"
    count/deployments.apps: "10"    # Generic format: count/.
    count/jobs.batch: "5"
    count/cronjobs.batch: "3"

Generic Count Syntax

# Format: count/.
count/deployments.apps         # Deployments in apps group
count/statefulsets.apps        # StatefulSets
count/ingresses.networking.k8s.io  # Ingresses
count/roles.rbac.authorization.k8s.io  # Roles

3. Storage Quotas

apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage-quota
  namespace: team-alpha
spec:
  hard:
    requests.storage: 500Gi              # Total PVC storage requests
    persistentvolumeclaims: "10"         # Max number of PVCs
    
    # Per-StorageClass quotas:
    gp3-encrypted.storageclass.storage.k8s.io/requests.storage: 200Gi
    gp3-encrypted.storageclass.storage.k8s.io/persistentvolumeclaims: "5"
    
    premium-iops.storageclass.storage.k8s.io/requests.storage: 100Gi
    premium-iops.storageclass.storage.k8s.io/persistentvolumeclaims: "2"
Storage quotas per StorageClass are critical in multi-tenant clusters. Without them, one team could provision unlimited premium IOPS volumes (expensive) or exhaust the cluster's storage capacity. Set generous quotas for standard storage, tight quotas for premium.

4. Quota Scopes — Targeting Specific Pods

Scopes let you apply quotas only to Pods matching certain criteria:

ScopeMatches Pods That...Use Case
BestEffortHave QoS class BestEffortLimit low-priority workloads
NotBestEffortHave QoS class Guaranteed or BurstableLimit "real" workloads
TerminatingHave activeDeadlineSeconds setLimit Jobs/short-lived Pods
NotTerminatingDon't have activeDeadlineSecondsLimit long-running services
PriorityClassMatch a specific PriorityClassPer-priority budgets

Priority Class Scoped Quotas

# Different budgets for different priority levels:
apiVersion: v1
kind: ResourceQuota
metadata:
  name: high-priority-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    pods: "5"
  scopeSelector:
    matchExpressions:
      - scopeName: PriorityClass
        operator: In
        values: ["high"]
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: low-priority-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "2"
    requests.memory: 4Gi
    pods: "20"
  scopeSelector:
    matchExpressions:
      - scopeName: PriorityClass
        operator: In
        values: ["low", "batch"]
Priority-scoped quotas enable fair sharing. A team gets 4 CPU for critical services (high priority) and 2 CPU for batch work (low priority). They can't use their batch quota for critical services or vice versa. This prevents one workload type from crowding out another.

5. Multi-Tenancy Pattern

# For a shared cluster with 3 teams:
# Total cluster: 48 CPU, 128Gi memory

# team-alpha namespace:    16 CPU, 40Gi   (33% of cluster)
# team-beta namespace:     16 CPU, 40Gi   (33% of cluster)
# platform namespace:      8 CPU, 32Gi    (shared services)
# Buffer (unallocated):    8 CPU, 16Gi    (headroom for bursting)

# Each namespace gets a ResourceQuota + LimitRange:
# Quota = budget ceiling
# LimitRange = per-Pod guardrails (min/max/defaults)
Quotas don't guarantee fair scheduling — they only limit creation. If team-alpha's Pods are scheduled first and fill nodes, team-beta's Pods might stay Pending even within quota. For true fairness, combine ResourceQuotas with PriorityClasses and the cluster autoscaler (new nodes spin up when resources are tight).

Summary

ConceptKey Point
ResourceQuotaNamespace-level hard cap on total resources consumed
Compute quotasCap requests.cpu/memory, limits.cpu/memory, pod count
Object count quotasCap number of Services, PVCs, Secrets, etc.
Storage quotasCap total PVC storage — can be per-StorageClass
EnforcementAt creation time only — existing Pods are not killed
LimitRange pairingRequired when compute quota exists (Pods must have resource specs)
ScopesApply quotas to subsets (BestEffort, PriorityClass, Terminating)
Multi-tenancyQuota per namespace = budget per team

📝 Quiz: ResourceQuotas

Q1: A namespace has a quota of requests.cpu: 4. Current total usage is 3.5 CPU. A developer tries to create a Pod with requests.cpu: 600m. What happens?

Rejected. 3.5 + 0.6 = 4.1, which exceeds the hard limit of 4. The Pod creation is denied by the quota admission controller with an error: "exceeded quota: requests.cpu used=3500m, requested=600m, limited=4000m."

Q2: You create a ResourceQuota with limits.memory: 8Gi. A developer creates a Pod without any resource spec. What happens?

Rejected with an error saying the Pod must specify limits.memory. When a compute ResourceQuota exists, every Pod must declare the corresponding resource fields so the quota can track them. Fix: add a LimitRange with default values — the LimitRanger injects them automatically.

Q3: The quota is reached (pods: 20). An existing Pod crashes (CrashLoopBackOff). Does the controller create a replacement?

A crashed Pod is still a Pod — it counts toward the quota (it hasn't been deleted). The kubelet restarts the container within the existing Pod, which doesn't create a new Pod object. Quota is not an issue here. But if the Pod is deleted and a Deployment tries to create a replacement while at 20/20, the new Pod creation succeeds (now 20/20 again after the delete freed a slot).

Q4: Can a ResourceQuota kill running Pods if the quota is reduced below current usage?

No. ResourceQuotas only enforce at creation time. If you reduce the quota below current usage, existing Pods continue running. No new Pods can be created until usage drops below the new limit (through natural scaling/termination). Quotas never actively kill Pods.

Q5: What's the format for limiting the number of Deployments in a namespace via ResourceQuota?

count/deployments.apps. The generic format is count/<resource>.<api-group>. For core group resources (Pods, Services), use the short names directly (pods, services). For non-core groups, use the full format.

Q6: Team Alpha has a quota of 8 CPU. They deploy 4 Pods at 2 CPU request each (total: 8). Now their cluster autoscaler wants to add a 5th Pod. Can they use a PriorityClass-scoped quota to get more?

Only if there are separate scoped quotas. If the 8 CPU quota has no scope (applies to all Pods), the 5th Pod is rejected regardless of priority. But if you split into two quotas — e.g., 6 CPU for "normal" priority and 4 CPU for "high" priority — the team gets a total of 10 CPU budget, partitioned by priority. Scoped quotas create independent pools.