Configuring ResourceQuotas and LimitRanges in Kubernetes
Imagine walking into a new project where the production namespace runs without a single ResourceQuota. A developer deploys a batch job with requests.cpu: 0 and limits.cpu: 0 — ie no limits at all. Within 20 minutes, that job consumes resources from two nodes, leaving other pods in Pending. According to the CNCF, missing quotas is one of the top three causes of instability in production clusters. Our clients often save up to 30% on cloud costs after implementing proper quotas. Without ResourceQuota, a single misconfigured pod can paralyze the entire cluster — like on our project with an online retailer, where a test namespace without limits ate half of the production resources.
According to official Kubernetes documentation, ResourceQuota limits aggregate resource consumption in a namespace, preventing cluster overload.
Why missing quotas is a ticking time bomb?
ResourceQuotas and LimitRanges solve different problems, but they are often confused. ResourceQuota caps the entire namespace — total CPU, memory, number of pods, services, PVCs. If the quota is exhausted, new objects are not created; kubectl apply returns an exceeded quota error. LimitRange works at the container level: it sets default requests/limits and min/max values. This is a safeguard against containers without explicit limits.
How to properly configure ResourceQuota and LimitRange?
We start with an audit: kubectl get resourcequota --all-namespaces reveals which namespaces lack quotas. Next, check which pods run without limits: kubectl get pods --all-namespaces -o json | jq '.items[] | select(.spec.containers[].resources.requests == null)'. Then we design the hierarchy. A typical multi-tenant cluster scheme:
| Namespace | requests.cpu | limits.cpu | requests.memory | limits.memory | Pods |
|---|---|---|---|---|---|
| production | 20 | 40 | 40Gi | 80Gi | 100 |
| staging | 8 | 16 | 16Gi | 32Gi | 50 |
| dev | 4 | 8 | 8Gi | 16Gi | 30 |
A LimitRange for dev looks like:
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "2"
memory: 2Gi
min:
cpu: 50m
memory: 64MiDefaults are a safety net: a container without explicit resources automatically gets 100m/128Mi, preventing it from hogging a node.
What to do if quotas conflict with HPA?
Another pitfall is LimitRange conflicting with HPA. If LimitRange sets max.cpu: 500m, and HPA tries to spin up a pod with limits.cpu: 1, the pod won't be created. Diagnose with kubectl describe events -n namespace | grep FailedCreate. The fix: either raise the max in LimitRange, or configure HPA with those limits in mind.
Comparison of ResourceQuota and LimitRange: which is better?
ResourceQuota is best for controlling namespace budget, while LimitRange prevents wasteful containers. Together they provide full control. ResourceQuota limits overall costs more effectively than LimitRange alone, because quotas apply to the sum of all containers. But without LimitRange, containers may lack explicit limits — then HPA could create pods that starve neighbors.
| Feature | ResourceQuota | LimitRange |
|---|---|---|
| Scope | Namespace | Container |
| What it limits | Total resources, object counts | CPU/memory per container |
| Defaults | No | Yes (default/request) |
Step-by-step quota implementation process
-
Audit current state: gather all namespaces, check for quotas and limits. Use
kubectl get resourcequota --all-namespacesand scripts to find pods without resources. - Analyze metrics from the last 30 days: export CPU and memory consumption per namespace from Prometheus, determine peak values and headroom. This is the basis for quota design.
- Design quotas: for each namespace, set requests and limits with 20-30% buffer above peak. Account for autoscaling and burst workloads.
- Write manifests: create YAML for ResourceQuota and LimitRange. For multi-tenant clusters, use templates with variables.
-
Test on staging: apply quotas first on dev and staging, check logs and events. Watch for errors like
exceeded quota. - Deploy to production: gradually, with monitoring via Alertmanager at 85% quota usage.
-
Document: record the quota schema, change rules, runbook for common errors (e.g.,
FailedCreatefrom LimitRange).
A typical mistake: a namespace with ResourceQuota fails to create pods. Error: pods "app-xyz-7d9f" is forbidden: exceeded quota: dev-quota, requested: requests.cpu=500m, used: requests.cpu=9800m, limited: requests.cpu=10. Solution: either increase the quota, or find who is holding resources with kubectl describe resourcequota dev-quota -n dev.
Common quota configuration mistakes
- Setting limits too low, which constantly denies pod creation
- Ignoring LimitRange, so containers without explicit resources get defaults, but not all developers are aware
- Not accounting for burst workloads: quotas shouldn't be rigid; need 20-30% headroom
What's included in the work
- Audit of current namespaces and pods
- Quota design based on load (collect metrics from the last 30 days)
- Writing ResourceQuota and LimitRange manifests
- Testing on staging environment
- Integration with Loki and Alertmanager for notifications
- Documentation and knowledge transfer to the team
Timelines
Simple configuration for 3–5 namespaces: 1 day. Multi-tenant cluster with dozens of teams and Prometheus integration: 2–3 days. Cloud cost savings after setup up to 30%, which at average monthly cloud spend of several thousand dollars yields a tangible effect. Investment in quota configuration typically pays back in 1–2 months.
Contact us for a cluster audit. Our engineers will help configure quotas and reduce costs. Order the ResourceQuota and LimitRange configuration service — get a stable cluster and budget savings.
Read more about ResourceQuota and LimitRange in the official documentation.







