KubernetesXIV · Namespace ArchitectureTenancy and isolation
ResourceQuota per namespace — capping total resource consumption
What you'll learn
- Configure ResourceQuota to cap total resource consumption per namespace
- Distinguish ResourceQuota from LimitRange (cap vs defaults)
- Reason about quota enforcement and the error a quota-exceeded Pod receives
- Apply quota sizing patterns for production
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
ResourceQuota is the namespace-level cap that prevents a team from consuming the entire cluster. This lesson covers quota configuration, the relationship with LimitRange, and the production discipline around quota sizing.
ResourceQuota anatomy
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-prod
namespace: team-a-prod
spec:
hard:
requests.cpu: "32"
requests.memory: 64Gi
limits.cpu: "64"
limits.memory: 128Gi
requests.ephemeral-storage: 100Gi
limits.ephemeral-storage: 200Gi
persistentvolumeclaims: "20"
requests.storage: 500Gi
services: "100"
secrets: "50"
configmaps: "100"
pods: "200"
The hard field is a set of limits. The total in the
namespace cannot exceed any of these.
The fields:
requests.cpu/requests.memory: total requests summed across all Pods.limits.cpu/limits.memory: total limits summed across all Pods.persistentvolumeclaims: max number of PVCs.requests.storage: total storage requested by PVCs.services,secrets,configmaps,pods: max object counts.
Quota enforcement
The quota admission plugin runs when:
- A Pod is created: the Pod’s requests and limits are added
to the running totals; if the new totals exceed
hard, the Pod is rejected. - A PVC is created: the storage request is added; if it
exceeds
hard, the PVC is rejected. - A ConfigMap/Secret/Service is created: the count is
incremented; if it exceeds
hard, the object is rejected.
The error message:
Error from server (Forbidden): error when creating "pod.yaml":
exceeded quota: team-a-prod,
requested: requests.cpu=1,requests.memory=1Gi,
used: requests.cpu=31,requests.memory=60Gi,
limited: requests.cpu=32,requests.memory=64Gi
The error shows the requested, used, and limited values. Operators can see exactly what quota was hit.
ResourceQuota vs LimitRange
The two work together:
| LimitRange | ResourceQuota | |
|---|---|---|
| Scope | Per-container | Per-namespace |
| Defaults | Yes (default, defaultRequest) | No |
| Constraints | Yes (min, max, maxLimitRequestRatio) | No |
| Totals | No | Yes (sum of all Pods) |
flowchart TD
Pod[Pod created] --> LR[LimitRange: applies defaults + per-container constraints]
LR --> RQ[ResourceQuota: checks namespace total]
RQ --> Allow{Passes?}
Allow -- yes --> Create[Pod created]
Allow -- no --> Reject[Pod rejected]
LimitRange ensures every Pod has resources (no BestEffort). ResourceQuota caps the total. Together: every Pod counts, and the total is bounded.
Production patterns
Team quota:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-prod
namespace: team-a-prod
spec:
hard:
requests.cpu: "32"
requests.memory: 64Gi
limits.cpu: "64"
limits.memory: 128Gi
persistentvolumeclaims: "20"
requests.storage: 500Gi
pods: "200"
This team gets 32 CPU / 64Gi requests and 64 CPU / 128Gi limits. They can have up to 200 Pods, 20 PVCs, and 500Gi of storage.
Environment-based quotas:
# Production: tighter limits
apiVersion: v1
kind: ResourceQuota
metadata:
name: prod
namespace: prod
spec:
hard:
requests.cpu: "100"
requests.memory: 200Gi
pods: "500"
---
# Development: more generous
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev
namespace: dev
spec:
hard:
requests.cpu: "200"
requests.memory: 400Gi
pods: "1000"
Production has tighter limits (predictable workloads); development has more (experimentation).
Quota and BestEffort Pods
A BestEffort Pod (no resources) does not count against
requests.cpu or requests.memory. But:
- It does count against
podsquota (every Pod counts). - It does count against
services,configmaps, etc.
Production discipline: pair ResourceQuota with LimitRange
to prevent BestEffort Pods. The pods quota is not enough.
Quota and PVCs
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-prod
namespace: team-a-prod
spec:
hard:
persistentvolumeclaims: "20"
requests.storage: 500Gi
Two fields:
persistentvolumeclaims: max number of PVCs in the namespace.requests.storage: total storage requested by PVCs.
A PVC with requests.storage: 100Gi counts 100Gi against
the quota. If the namespace already has 450Gi in use, a new
50Gi PVC succeeds; a new 100Gi PVC would be rejected.
Monitoring quota usage
kubectl describe resourcequota team-a-prod -n team-a-prod
Output:
Name: team-a-prod
Namespace: team-a-prod
Resource Used Hard
-------- ---- ----
requests.cpu 24 32
requests.memory 48Gi 64Gi
limits.cpu 48 64
limits.memory 96Gi 128Gi
pods 84 200
The Used column shows current usage; Hard shows the
quota. Production discipline: monitor quota usage; alert
when usage > 80%.
# Quota usage ratio
kube_resourcequota{resource="requests.cpu", type="used"}
/ kube_resourcequota{resource="requests.cpu", type="hard"}
> 0.8
Alert when quota usage exceeds 80% of the hard limit. The team needs a quota increase.
Production discipline
Size quotas based on team needs:
- Small team / dev: 8 CPU, 16Gi memory, 50 Pods.
- Medium team / staging: 32 CPU, 64Gi memory, 200 Pods.
- Large team / prod: 100 CPU, 200Gi memory, 500 Pods.
Size based on actual usage; raise as teams grow.
Pair with LimitRange:
# LimitRange: defaults
apiVersion: v1
kind: LimitRange
metadata:
name: default
namespace: team-a-prod
spec:
limits:
- type: Container
default: {cpu: 500m, memory: 512Mi}
defaultRequest: {cpu: 100m, memory: 128Mi}
# ResourceQuota: namespace total
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-prod
namespace: team-a-prod
spec:
hard:
requests.cpu: "32"
requests.memory: 64Gi
LimitRange ensures every Pod has resources; ResourceQuota caps the total. Together, a complete resource policy.
- Monitor quota usage. Alert when usage > 80%; review with the team before hitting the limit.
- Use StorageClass-specific quotas to control expensive storage usage.
- Document the quota increase process. Teams need a clear path to get more capacity when they need it.
Cross-course references
- The Linux course part
XXXVII-Linux-Resourcescovers cgroup resource management; ResourceQuota is the cluster-level equivalent for namespaces. - The Ansible course part
XLIX-Ansible-Compliancecovers policy compliance; ResourceQuota is the cluster-level equivalent. - The Observability course part
LXXXIV-Kubernetes-CapacityPlanningcovers capacity planning; quotas are part of the plan.
Quiz
Knowledge check · 4 questions
Q1. What is the difference between ResourceQuota and LimitRange?
Q2. A BestEffort Pod (no resources) bypasses ResourceQuota because it has no requests to count.
Q3. A team's Deployment of 50 replicas hits the namespace's `pods: 100` quota. The team cannot deploy until quota is raised. Walk through the diagnosis and the fix.
Team `team-a-prod` has ResourceQuota with `pods: 100`. The team currently has 95 Pods running. The team wants to deploy a new Deployment with 10 replicas. Total would be 105 Pods; quota is 100. The Deployment fails.
Q4. How do you size a ResourceQuota for a new team namespace?
Passing score: 75%. Answers are checked in this browser.