2026
Kubernetes ResourceQuota: Protecting a Shared Cluster
In a shared cluster, nothing stops one namespace from consuming all available CPU and memory. ResourceQuota changes that by setting hard limits on what a namespace can request. One object, applied once, protects the rest of the cluster from runaway workloads.
A Kubernetes cluster is a shared resource. Multiple teams, multiple applications, multiple environments can all live inside the same cluster at the same time. That sharing is part of the value. It is also the source of a particular category of problems.
Without any constraints in place, a single namespace can consume all available CPU and memory in the cluster. A misconfigured deployment that requests enormous amounts of memory will happily starve out every other workload on whatever nodes it lands on. A script that accidentally creates objects in a loop will fill etcd until the API server starts struggling. None of this requires malicious intent. It just requires the absence of limits.
ResourceQuota is the mechanism Kubernetes provides to set those limits. It lives in a namespace and defines ceilings on the resources that namespace is allowed to consume. Once a quota is set, requests that would push usage past the limit are rejected at admission. The rest of the cluster is protected.
How it works
ResourceQuota is an admission controller built into Kubernetes. When you create a ResourceQuota object in a namespace, the admission controller starts tracking usage for every resource type the quota covers. Each time a new object is created in that namespace, the controller checks whether the new object would push cumulative usage over any of the defined limits. If it would, the request is rejected. If it would not, the object is created and the usage count is updated.
The quota tracks usage across the entire namespace, not per workload. Ten pods each requesting 100m CPU consume 1000m of the namespace's CPU request quota. Deleting one pod frees 100m. The counts are live: they reflect actual objects in the namespace at any moment. You can inspect them with kubectl describe resourcequota to see how much of each limit is used versus how much remains.
Worth noting
ResourceQuota applies to new object creation. Existing objects that already exceed the quota limits are not evicted when a quota is first applied. The quota begins enforcing from the moment it is created onward. This means you can apply a quota to a namespace that is already running workloads without immediately disrupting anything, but usage may already be above the limit you specified and no new objects will be accepted until usage drops below it.
What you can limit
ResourceQuota covers several distinct categories of resources. Most production configurations use a combination rather than limiting just one type.
Compute quotas
Limit the total CPU and memory that all pods in a namespace can request. The two fields are requests.cpu, requests.memory, limits.cpu and limits.memory. Requests are what the scheduler uses to find a node. Limits are the ceiling the container runtime enforces at runtime. Quotas on both prevent a namespace from monopolising cluster capacity even if individual pods have modest requests.
Object count quotas
Cap the number of a particular kind of object that can exist in the namespace. You can limit the number of Pods, Services, ConfigMaps, Secrets, PersistentVolumeClaims and most other resource types. A team that accidentally creates thousands of ConfigMaps in a loop can affect etcd performance for the whole cluster. Object count quotas make that class of mistake bounded.
Storage quotas
Restrict the total storage capacity requested through PersistentVolumeClaims. The requests.storage field limits the sum of all PVC requests in the namespace. You can also restrict per StorageClass, which lets you say that a namespace may use at most fifty gigabytes of SSD storage while having a separate limit for standard disk.
Scope selectors
Quotas can be scoped so they only count objects that match a condition. The built-in scopes include Terminating, NotTerminating, BestEffort and NotBestEffort, which filter by pod lifecycle state and quality of service class. A scope selector using PriorityClass lets you apply separate quotas to high-priority pods so critical workloads are not blocked by the general namespace quota.
What a ResourceQuota looks like
The manifest lists each resource type under a hard block. The names correspond directly to the fields Kubernetes tracks. Compute resources use the same unit notation as container resource fields. Object counts are plain integers.
ResourceQuota for a team namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
requests.storage: 50Gi
pods: "20"
services: "10"
secrets: "30"
configmaps: "20"
persistentvolumeclaims: "10"
CPU values can be written as whole numbers, decimals like 0.5 or milliCPU like 500m. Memory follows the same unit notation used everywhere else in Kubernetes: Mi, Gi and so on. Object counts are strings in the YAML but represent integers. Kubernetes will reject the manifest if the value cannot be parsed as a non-negative integer.
Checking quota usage
The kubectl describe resourcequota command shows current usage against each limit. This is the fastest way to understand whether a namespace is approaching its ceiling or has plenty of headroom.
kubectl describe resourcequota team-quota -n team-alpha
Name: team-quota
Namespace: team-alpha
Resource Used Hard
-------- ---- ----
configmaps 7 20
limits.cpu 3500m 8
limits.memory 6Gi 16Gi
persistentvolumeclaims 3 10
pods 11 20
requests.cpu 1750m 4
requests.memory 3Gi 8Gi
requests.storage 15Gi 50Gi
secrets 12 30
services 4 10
This namespace is roughly halfway through most of its limits. The pod count at eleven out of twenty is worth watching. CPU limits at 3500m out of 8000m still have plenty of room. Any team or platform tool that monitors these values can alert before a limit is hit rather than after pods start failing to schedule.
LimitRange: the companion object
ResourceQuota and LimitRange are often deployed together. ResourceQuota sets namespace-level ceilings. LimitRange sets per-container defaults and bounds. They solve different problems and each is less useful without the other.
Default requests and limits
If a container is created without specifying requests or limits, LimitRange fills in defaults. This matters because a namespace with a ResourceQuota on compute will reject any pod that does not have requests set. Without defaults, every developer must remember to set them. With defaults, the guardrails work even for manifests that do not include resource fields.
Minimum and maximum bounds
LimitRange can enforce that no container in the namespace requests less than a minimum amount or more than a maximum. A container requesting one thousand CPUs would be rejected at admission. A container requesting zero memory would also be rejected. This prevents misconfigured manifests from either wasting quota or starving on a node.
Limit to request ratio
You can set a maximum ratio between the limit and the request for a container. If the ratio is two, a container that requests 100m CPU cannot set a limit above 200m. This prevents the practice of setting extremely low requests to pass scheduling while setting enormous limits that the node cannot actually sustain when multiple pods compete.
LimitRange — defaults and bounds for containers
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: team-alpha
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 512Mi
min:
cpu: 50m
memory: 64Mi
max:
cpu: "2"
memory: 4Gi
Things that go wrong
Most ResourceQuota problems surface as unexpected admission rejections. The error messages are specific but can be confusing if you are not familiar with the quota model.
Quota with no LimitRange
A ResourceQuota on compute resources will reject pods that do not specify requests. If no LimitRange is set to provide defaults, every pod manifest in the namespace must include resource fields. Teams that apply a quota without also setting up a LimitRange usually discover this the hard way when deployments start failing with admission errors.
Setting limits without requests
Some teams set only limits on containers, not requests. Kubernetes then sets the request equal to the limit. This makes the scheduler treat the container as using its full limit at all times, which can leave nodes looking full when they are not. Quota consumption also looks higher than actual usage. Requests and limits serve different purposes and both should be set deliberately.
Quota applied to the wrong namespace
ResourceQuota is namespaced. It only applies to the namespace it lives in. A quota in the production namespace does nothing to constrain the staging namespace. In clusters where the same application runs in multiple namespaces, quotas need to be applied to each one independently.
Not reviewing quota status
Once a quota is set and forgotten, the namespace quietly approaches its limits over time. When the limit is hit, new pods fail to schedule with cryptic admission errors. Regularly checking the used versus hard values in quota status, or alerting when usage crosses a threshold, prevents this from becoming an incident.
Where it fits
ResourceQuota sits at the boundary between a namespace and the rest of the cluster. Namespaces provide isolation at the API level: objects in one namespace do not collide with objects in another. Quotas add resource isolation on top of that. Without quotas, namespace isolation is logical but not physical. One noisy namespace can affect every other workload in the cluster through resource contention.
In multi-tenant clusters where different teams share infrastructure, quotas are often a prerequisite for giving teams autonomy. Without them, a platform team would need to review every deployment to ensure no single team is taking more than their fair share. With quotas in place, teams can deploy freely up to their allocation. The platform team sets the limits and lets the teams self-serve within them.
ResourceQuota works alongside RBAC and network policies as part of a broader namespace isolation strategy. RBAC controls who can do what. Network policies control which pods can talk to which other pods. ResourceQuota controls how much of the cluster a namespace can consume. Each addresses a different dimension of isolation. Relying on any one of them in isolation leaves the other dimensions unguarded.