ResourceQuota and LimitRange
“https://kubernetes.io/docs/concepts/policy/resource-quotas/”
ResourceQuota and LimitRange are the two namespace-level policy objects that constrain what a namespace can use. They’re how a cluster admin or platform team enforces “this namespace gets at most 100 GB of storage and 50 cores” or “Pods in this namespace can request at most 8 GB of memory each”.
This note covers:
- ResourceQuota — aggregate limits for a namespace (total CPU, total memory, total storage, object counts, etc.).
- LimitRange — per-object limits and defaults (e.g. “every container in this namespace gets a default 100m CPU request if not specified”).
These are complementary — ResourceQuota is the ceiling, LimitRange is the floor and per-object constraint.
Table of Contents
- The Two-Policy Model
- ResourceQuota — Aggregate Namespace Limits
- ResourceQuota Specification in Detail
- Compute Quotas (CPU / Memory / Ephemeral Storage)
- Storage Quotas
- Object Count Quotas
- Extended Resources (GPU, etc.)
- LimitRange — Per-Object Defaults and Constraints
- LimitRange Specification in Detail
- The Pod’s View: How Quotas Affect Scheduling
- Operations and Debugging
- Gotchas and Common Mistakes
1. The Two-Policy Model
Namespace
│
┌─────────────┴─────────────┐
│ │
▼ ▼
ResourceQuota LimitRange
(aggregate ceiling) (per-object floor / ceiling)
│ │
│ - total CPU: 50 │ - default request per container
│ - total memory: 200Gi │ - max request per Pod
│ - total storage: 1Ti │ - max storage per PVC
│ - max Pods: 100 │ - default storage request
│ - max ConfigMaps: 200 │ - min storage request
│ │
▼ ▼
"Can't create more "Every Pod/Container/PVC in this
because quota exceeded" namespace has these constraints"
1.1 Why two objects
- ResourceQuota is about the namespace as a whole — how much total resource consumption is allowed.
- LimitRange is about individual objects — what each Pod, Container, or PVC can request or limit.
A team might set:
ResourceQuota: “this namespace gets at most 100 cores and 500 GB of memory”LimitRange: “every container in this namespace must request at least 100m CPU, can’t request more than 8 cores”
The ResourceQuota says “the namespace is full, you can’t add more Pods”. The LimitRange says “this individual Pod is too big, you need to shrink it”.
1.2 Are they required?
No. A namespace without a ResourceQuota and without a LimitRange has no constraints. Pods can request any amount, the namespace can have any number of objects.
Most production namespaces have at least one of these. Best practice is both — a ResourceQuota for the namespace ceiling, a LimitRange for per-Pod safety.
2. ResourceQuota — Aggregate Namespace Limits
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: prod
spec:
hard:
requests.cpu: "50"
requests.memory: 200Gi
limits.cpu: "100"
limits.memory: 400Gi
persistentvolumeclaims: "20"
requests.storage: 1Ti
requests.ephemeral-storage: 100Gi
limits.ephemeral-storage: 200Gi
pods: "100"
configmaps: "200"
secrets: "100"
services: "50"
services.loadbalancers: "5"
services.nodeports: "5"
count/jobs.batch: "10"
count/cronjobs.batch: "20"This says: “the prod namespace can have at most 50 cores of CPU requested, 200 GB of memory requested, 100 cores of CPU limited, etc.”
2.1 What happens when quota is exceeded
When you try to create a Pod (or PVC, etc.) that would exceed the quota:
$ kubectl run test --image=busybox --requests='cpu=1' --restart=Never
Error from server (Forbidden):
pods "test" is forbidden:
exceeded quota: compute-quota,
requested: requests.cpu=1,
used: requests.cpu=50, limited: requests.cpu=50
The resource isn’t created. The error tells you which quota and what’s over.
For PVCs:
$ kubectl apply -f big-pvc.yaml
Error from server (Forbidden):
persistentvolumeclaims "big-pvc" is forbidden:
exceeded quota: storage-quota,
requested: requests.storage=2Ti,
used: requests.storage=1Ti, limited: requests.storage=1Ti
2.2 Quota is namespace-scoped
ResourceQuota lives in a namespace and applies to that namespace only. Different namespaces can have different quotas.
metadata:
namespace: prod # this quota applies to the prod namespaceCross-namespace quotas are not a thing. To limit the entire cluster, you’d need a controller that aggregates per-namespace quotas.
2.3 Quota is enforced at admission
The ResourceQuota is enforced by the admission controller in the apiserver. When you create a Pod:
- The apiserver receives the request.
- The ResourceQuota admission plugin checks: “would creating this Pod exceed any quota in the namespace?”
- If yes, the request is rejected.
- If no, the request proceeds.
The Pod’s resource requests are what count, not its actual usage. A Pod that requests 1 CPU but uses 10 millicores still counts as 1 CPU against the quota.
2.4 Quota is observed
The apiserver updates the ResourceQuota’s status.used field as resources are allocated. You can see the current usage:
kubectl describe resourcequota <name> -n <namespace>
# shows the hard limits, the used, and the difference3. ResourceQuota Specification in Detail
apiVersion: v1
kind: ResourceQuota
metadata:
name: full-quota
namespace: prod
spec:
hard:
# compute
requests.cpu: "50"
requests.memory: 200Gi
limits.cpu: "100"
limits.memory: 400Gi
requests.ephemeral-storage: 100Gi
limits.ephemeral-storage: 200Gi
# storage
requests.storage: 1Ti
persistentvolumeclaims: "20"
# object counts
pods: "100"
configmaps: "200"
secrets: "100"
services: "50"
services.loadbalancers: "5"
services.nodeports: "5"
replicationcontrollers: "20"
resourcequotas: "5" # max number of ResourceQuotas in the namespace
# typed object counts
count/jobs.batch: "10"
count/cronjobs.batch: "20"
count/deployments.apps: "50"
count/statefulsets.apps: "10"
# extended resources
requests.nvidia.com/gpu: "8"
limits.nvidia.com/gpu: "8"
scopes:
- NotTerminating # only count non-terminal Pods
# OR
scopes:
- BestEffort # only count BestEffort Pods
# OR
scopes:
- Terminating # only count terminating Pods3.1 The scopes field
By default, the quota counts all Pods (BestEffort, Burstable, Guaranteed, and Terminating). You can scope the quota to a subset:
| Scope | Applies to |
|---|---|
Terminating | Pods with activeDeadlineSeconds set, or Jobs |
NotTerminating | All other Pods (the default) |
BestEffort | Pods with no resource requests/limits set |
NotBestEffort | Pods with at least one resource request/limit set |
Example: you want to limit Burstable / Guaranteed Pods but not BestEffort:
spec:
scopes:
- NotBestEffort
hard:
requests.cpu: "50"
requests.memory: 200GiBestEffort Pods (no requests) are unlimited; Burstable / Guaranteed are constrained.
Example: you want to limit Jobs separately from long-running Pods:
# quota for long-running Pods
apiVersion: v1
kind: ResourceQuota
metadata:
name: long-running
spec:
scopes:
- NotTerminating
hard:
pods: "50"
requests.cpu: "30"
---
# quota for Jobs
apiVersion: v1
kind: ResourceQuota
metadata:
name: jobs
spec:
scopes:
- Terminating
hard:
requests.cpu: "100"
count/jobs.batch: "20"Now you can have at most 50 long-running Pods and at most 20 Jobs, with separate CPU ceilings.
4. Compute Quotas (CPU / Memory / Ephemeral Storage)
spec:
hard:
requests.cpu: "50" # total CPU requested by all Pods
requests.memory: 200Gi # total memory requested by all Pods
limits.cpu: "100" # total CPU limits across all Pods
limits.memory: 400Gi # total memory limits across all Pods
requests.ephemeral-storage: 100Gi # total ephemeral storage requested
limits.ephemeral-storage: 200Gi # total ephemeral storage limits4.1 Requests vs limits
A Pod can have both requests and limits. The quota can constrain each separately.
requests.cpuandrequests.memory— the sum of all Pods’ requests must not exceed this. The scheduler uses this for placement.limits.cpuandlimits.memory— the sum of all Pods’ limits must not exceed this. The kubelet enforces this at runtime.
Why have both? A common pattern is:
requests.cpu: 50— at most 50 cores of “guaranteed” capacity.limits.cpu: 100— Pods can burst up to 100 cores (overcommit).
This lets you overcommit, with the scheduler placing based on requests and the kubelet throttling based on limits.
4.2 The “Burstable QoS” implication
A Pod with requests: {cpu: 100m} and limits: {cpu: 1} is Burstable. It uses 100m against the request quota and 1 against the limit quota. Both numbers count.
A Pod with requests: {cpu: 1} and no limit is also Burstable (no limit = node capacity, but quota-wise the limit is the same as the request).
A Pod with requests == limits for both CPU and memory is Guaranteed. The numbers are the same.
4.3 Overcommitment math
If you have 10 nodes, each with 16 cores = 160 cores of cluster capacity.
requests.cpu: 80— at most 80 cores of guaranteed capacity (50% overcommit).limits.cpu: 160— Pods can use up to 100% of cluster capacity.
This is a common setup. The scheduler uses the request for placement (so we don’t overcommit placement), the kubelet uses the limit for throttling (so we don’t OOM the node).
5. Storage Quotas
spec:
hard:
requests.storage: 1Ti # total storage requested by all PVCs
persistentvolumeclaims: "20" # max number of PVCs
requests.ephemeral-storage: 100Gi # total ephemeral storage requested (emptyDir, etc.)
limits.ephemeral-storage: 200Gi # total ephemeral storage limits5.1 requests.storage vs persistentvolumeclaims
requests.storage— the sum of all PVCs’spec.resources.requests.storage.persistentvolumeclaims— the count of PVCs.
A single namespace can have:
- 20 PVCs, each 50 GiB = 1 TiB total (
requests.storage: 1Ti). - 5 PVCs, each 200 GiB = 1 TiB total.
- 100 PVCs, each 10 GiB = 1 TiB total (but
persistentvolumeclaims: 20would block the 21st).
The two constraints are independent. You can have 20 PVCs totaling 10 TiB if you only set persistentvolumeclaims: 20.
5.2 Storage class-specific quotas
spec:
hard:
requests.storage: 1Ti # total across all classes
gold.storageclass.requests.storage: 500Gi # total for the gold class
silver.storageclass.requests.storage: 500Gi # total for the silver classThis constrains the total storage for each StorageClass. Useful for:
- Tiered storage — limit how much high-perf storage a namespace can use.
- Cost control — gp3 vs io2 vs sc1 have very different costs.
5.3 PVC count vs total storage
You can have:
spec:
hard:
persistentvolumeclaims: "20"
requests.storage: 1TiA namespace with 20 PVCs of 50 GiB each is at the limit. A namespace with 20 PVCs of 100 GiB each is over the storage quota but at the count limit.
Both constraints must be satisfied. Either can block a new PVC.
6. Object Count Quotas
spec:
hard:
pods: "100"
configmaps: "200"
secrets: "100"
services: "50"
services.loadbalancers: "5"
services.nodeports: "5"
replicationcontrollers: "20"
resourcequotas: "5"These count objects of the given type in the namespace. Some examples:
pods: 100— at most 100 Pods in the namespace (regardless of resource requests).services: 50— at most 50 Services.services.loadbalancers: 5— at most 5 LoadBalancer Services (a subset ofservices).services.nodeports: 5— at most 5 NodePort Services.
6.1 Typed object counts
spec:
hard:
count/jobs.batch: "10"
count/cronjobs.batch: "20"
count/deployments.apps: "50"
count/statefulsets.apps: "10"
count/daemonsets.apps: "20"The format is count/<resource>.<api-group>. The api-group is the part after the slash in the apiVersion (apps/v1 → apps).
This is useful for:
- Restricting who can create what — only 10 StatefulSets, but unlimited Deployments.
- Cost control — LoadBalancer Services cost money; limit them.
7. Extended Resources (GPU, etc.)
spec:
hard:
requests.nvidia.com/gpu: "8"
limits.nvidia.com/gpu: "8"Extended resources are opaque to k8s — they’re reported by nodes (via the kubelet’s --node-labels or the device plugin) and consumed by Pods. The most common is GPU:
containers:
- name: ml
image: tensorflow/tensorflow:latest-gpu
resources:
requests:
nvidia.com/gpu: 1
limits:
nvidia.com/gpu: 1The ResourceQuota can constrain how many GPUs a namespace can request.
Other extended resources:
nvidia.com/gpu— NVIDIA GPUsamd.com/gpu— AMD GPUsintel.com/sgx— Intel SGX enclaves- Custom resources from device plugins (FPGAs, InfiniBand, etc.)
The quota format is requests/<resource-domain>/<resource-name> and limits/<resource-domain>/<resource-name>.
8. LimitRange — Per-Object Defaults and Constraints
A LimitRange sets per-object defaults and constraints in a namespace. It’s the “floor” and “ceiling” for individual objects.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: prod
spec:
limits:
- type: Container
default: # applied if not set in the Pod
cpu: 500m
memory: 512Mi
defaultRequest: # applied if not set in the Pod
cpu: 200m
memory: 256Mi
max: # max allowed per container
cpu: "2"
memory: 4Gi
min: # min allowed per container
cpu: 100m
memory: 128Mi
maxLimitRequestRatio: # max ratio of limit:request
cpu: 4
memory: 2
- type: Pod
max: # max total per Pod (sum of all containers)
cpu: "8"
memory: 16Gi
- type: PersistentVolumeClaim
max:
storage: 100Gi
min:
storage: 1Gi
- type: PersistentVolumeClaim
max:
storage: 1Ti
min:
storage: 10Gi
default:
storage: 100Gi
defaultRequest:
storage: 50GiThis is per-Pod, per-Container, and per-PVC constraints and defaults. The defaults are applied automatically to Pods / PVCs that don’t specify the field.
8.1 The four types
| Type | Applies to | What it can do |
|---|---|---|
Container | Each container in a Pod | default, defaultRequest, max, min, maxLimitRequestRatio |
Pod | Each Pod (sum of all containers) | max (only) |
PersistentVolumeClaim | Each PVC | default, defaultRequest, max, min |
PersistentVolume | Each PV (cluster-wide) | max, min (rarely used) |
8.2 The default and defaultRequest fields
These are the defaults applied to objects that don’t specify the field.
default.cpu: 500m— if a Container doesn’t specifylimits.cpu, set it to 500m.defaultRequest.cpu: 200m— if a Container doesn’t specifyrequests.cpu, set it to 200m.
The default is what the user gets if they don’t say. The defaultRequest is the same for requests. The defaults can be overridden by the Pod’s spec, but the max and min are hard constraints.
8.3 The max and min fields
Hard constraints on individual values:
max.cpu: 2— no Container can request more than 2 cores.min.memory: 128Mi— no Container can request less than 128 MiB.
A Pod that violates a max or min is rejected at admission.
8.4 The maxLimitRequestRatio
The maximum allowed ratio of limit:request for a single resource:
maxLimitRequestRatio:
cpu: 4 # limit can be at most 4x the request
memory: 2 # limit can be at most 2x the requestIf a Pod sets requests.cpu: 500m, limits.cpu: 1, the ratio is 1/0.5 = 2, which is ≤ 4. Allowed.
If a Pod sets requests.cpu: 500m, limits.cpu: 4, the ratio is 4/0.5 = 8, which is > 4. Rejected.
This is a “don’t overcommit too much” guard. It prevents Pods from setting tiny requests but huge limits (which would be a free-for-all).
9. LimitRange Specification in Detail
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: prod
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
ephemeral-storage: 1Gi
defaultRequest:
cpu: 200m
memory: 256Mi
ephemeral-storage: 100Mi
max:
cpu: "2"
memory: 4Gi
ephemeral-storage: 10Gi
min:
cpu: 100m
memory: 128Mi
ephemeral-storage: 10Mi
maxLimitRequestRatio:
cpu: 4
memory: 2
ephemeral-storage: 10
- type: Pod
max:
cpu: "8"
memory: 16Gi
ephemeral-storage: 50Gi
- type: PersistentVolumeClaim
max:
storage: 1Ti
min:
storage: 1Gi
default:
storage: 100Gi
defaultRequest:
storage: 10Gi9.1 How defaults are applied
When a Pod is created in the namespace:
- If the Pod has no
containers[].resources.requests.cpu, the LimitRange’sdefaultRequest.cpuis applied. - If the Pod has no
containers[].resources.limits.cpu, the LimitRange’sdefault.cpuis applied. - The Pod’s effective resources are checked against
maxandmin. - If violations, the Pod is rejected.
Defaults don’t change the Pod’s spec — they only apply at admission. The Pod’s spec remains as the user wrote it. (You can see the defaults via kubectl describe pod or by querying the apiserver with ?includeUninitialized=....)
9.2 The “BestEffort” trap
A Pod with no requests or limits is BestEffort QoS. The LimitRange’s defaultRequest doesn’t apply (it requires a request to be defaulted). BestEffort Pods are unlimited.
To prevent BestEffort Pods, use a ResourceQuota with the BestEffort scope negation:
# Allow only Burstable / Guaranteed Pods
apiVersion: v1
kind: ResourceQuota
metadata:
name: no-besteffort
spec:
scopes:
- NotBestEffort
hard:
pods: "100"This counts Burstable and Guaranteed Pods only. BestEffort Pods aren’t counted by this quota (they’re unlimited by it), but they aren’t blocked either. To block BestEffort Pods, use a NetworkPolicy or a custom admission webhook.
10. The Pod’s View: How Quotas Affect Scheduling
A Pod’s resource requests are what count against the quota. The scheduler uses the requests for placement.
10.1 The flow
User creates Pod (requests.cpu=1, requests.memory=1Gi)
│
▼
admission: check ResourceQuota
│
├── quota OK → Pod is created
│
└── quota exceeded → Pod is rejected with 403 Forbidden
10.2 Quota and the scheduler
The scheduler places Pods based on the node’s available resources (sum of node capacity minus sum of Pods’ requests). The ResourceQuota is a separate, additional constraint — it limits the namespace, not the cluster.
Cluster capacity: 160 cores
Namespace quota: requests.cpu: 50
Total requests in namespace: 50 cores
Total requests on nodes: 40 cores
A new Pod requests 2 cores.
- Scheduler: 40 + 2 = 42 < 160. Plenty of cluster capacity. OK.
- Quota: 50 + 2 = 52 > 50. Quota exceeded. Reject.
The Pod is rejected even though the cluster has plenty of capacity. The namespace is full.
10.3 The “quota exceeded” 403
When the quota blocks a Pod, the error is:
Error from server (Forbidden):
pods "my-pod" is forbidden:
exceeded quota: compute-quota,
requested: requests.cpu=2,requests.memory=1Gi,
used: requests.cpu=50,requests.memory=200Gi,
limited: requests.cpu=50,requests.memory=200Gi
The error tells you which quota, what you requested, what’s used, and what’s the limit. The Pod is not created. kubectl describe pod will show the same error in events.
For PVCs:
Error from server (Forbidden):
persistentvolumeclaims "my-pvc" is forbidden:
exceeded quota: storage-quota,
requested: requests.storage=1Ti,
used: requests.storage=1Ti,
limited: requests.storage=1Ti
10.4 What quota doesn’t do
- Quota doesn’t move existing Pods to a different node. It only blocks new creations / updates.
- Quota doesn’t evict Pods. A Pod that’s already running is fine, even if the namespace is now over quota (rare, but possible if the quota was reduced).
- Quota doesn’t care about actual usage. A Pod that requests 1 CPU but uses 10 millicores still counts as 1 CPU.
11. Operations and Debugging
11.1 Common commands
# list ResourceQuotas
kubectl get resourcequota -A
# or
kubectl get quota -A
# describe
kubectl describe resourcequota <name> -n <namespace>
# shows hard limits, used, and the difference
# the same for LimitRange
kubectl get limitrange -A
kubectl describe limitrange <name> -n <namespace>
# check the current usage
kubectl describe resourcequota <name> -n <namespace> | grep -A 20 "Used"
# check why a Pod was rejected
kubectl describe pod <pod> -n <namespace>
# look for "exceeded quota" in events11.2 The “Pod is forbidden” debugging
$ kubectl create -f pod.yaml
Error from server (Forbidden): ...
- Read the error message. It tells you which quota, what’s used, what’s requested, what’s the limit.
- Check the quota’s current state:
kubectl describe resourcequota <name> -n <namespace>. - Options:
- Increase the quota (
kubectl edit resourcequota). - Reduce the Pod’s requests.
- Delete unused resources in the namespace.
- Move the Pod to a different namespace.
- Increase the quota (
11.3 The “PVC is forbidden” debugging
Same as Pod, but for PVCs. The error message tells you which storage quota is exceeded.
11.4 The “my Pod has no resource requests but should”
This is a LimitRange issue. The LimitRange has defaultRequest for the namespace, but the Pod has no requests — which means the Pod is BestEffort (unbounded).
Fix: either set the Pod’s requests explicitly, or make the LimitRange’s defaultRequest apply (it only applies to Pods with at least one resource set, not entirely empty Pods).
Actually, re-reading the docs: the LimitRange’s defaultRequest IS applied to Pods that don’t have requests. So a LimitRange with defaultRequest: {cpu: 200m, memory: 256Mi} would set those for a Pod with no requests.
Verify with:
kubectl get pod <pod> -o yaml
# look at spec.containers[].resources
# should have the defaults applied12. Gotchas and Common Mistakes
12.1 The 25+ common mistakes
-
A namespace without a ResourceQuota and LimitRange is unbounded. A user can request 1000 cores and 1 PB of memory, and the apiserver accepts it.
-
ResourceQuota is enforced at admission, not at runtime. A Pod that already exists is not evicted if the quota is reduced. New Pods are blocked.
-
A Pod’s resource REQUESTS are what count, not its actual usage. A Pod that requests 1 CPU but uses 10 millicores counts as 1 CPU against the quota.
-
The
requests.cpuandlimits.cpuquotas are independent. A Pod’s request counts againstrequests.cpu, its limit counts againstlimits.cpu. Set both. -
BestEffort Pods are not counted by the
NotBestEffortquota scope. They have no requests, so they don’t count. To limit them, use a separate quota or a NetworkPolicy / custom admission webhook. -
LimitRange’s
defaultRequestis applied at admission. It doesn’t change the Pod’s spec, but the effective request is what the scheduler sees.kubectl describe podshows the default. -
The
maxLimitRequestRatiois a per-resource setting. Set it for each resource individually (cpu: 4, memory: 2), not as a single value. -
The
Podtype’smaxis the sum of all containers in the Pod. A Pod with 2 containers, each requesting 2 cores, violates aPod.max.cpu: 2(even if each container is below the Containermax). -
The
PersistentVolumeClaimtype’smaxis per-PVC, not aggregate. A quota ofmax.storage: 100Gimeans each PVC can be at most 100 GiB. The aggregate is constrained by the ResourceQuota’srequests.storage. -
A namespace can have multiple ResourceQuotas. They all apply. A new resource must satisfy all of them.
-
A namespace can have multiple LimitRanges. They all apply. A new object must satisfy all of them.
-
The
services.loadbalancersquota is a subset ofservices. If you setservices: 10andservices.loadbalancers: 2, you can have at most 10 Services, of which at most 2 are LoadBalancer. -
The
resourcequotasquota limits the number of ResourceQuotas in a namespace. Useful to prevent admin sprawl. Set it to 1 or 5. -
The default StorageClass is used by PVCs without
storageClassName. The default class isn’t constrained by the per-class storage quota unless you set one. A PVC using the default class counts against the namespace’srequests.storage, not the per-class quota. -
Per-storage-class quotas require the StorageClass to be installed. A quota like
gp3.storageclass.requests.storage: 500Gionly works if thegp3StorageClass is installed. Otherwise, no PVC can use it. -
The
count/<resource>.<api-group>format is case-sensitive.count/deployments.appsis correct.count/Deployments.Appsis not. -
The
requests.ephemeral-storageandlimits.ephemeral-storageare for emptyDir, container overlay, etc. Not for PVCs. -
LimitRange’s
defaultfor PersistentVolumeClaim is thelimitsequivalent. It applies to the PVC’sspec.resources.limits.storage(if set). Wait, actually it applies to the request… let me re-check.
Actually, for PVCs, default and defaultRequest are both supported. The behavior is similar to Container:
defaultRequest.storageis applied ifspec.resources.requests.storageis not set.default.storageis applied ifspec.resources.limits.storageis not set.
But for PVCs, the standard is to use requests (the limit is the same as the request). So default and defaultRequest are usually the same.
-
A LimitRange with
max: 0blocks all creations. Useful for “freeze” scenarios. -
A LimitRange with no
minand nomaxis just defaults. It’s not a hard constraint; it just sets the values for objects that don’t specify them. -
Quota doesn’t apply to completed Jobs. Once a Job is done, it’s in
CompleteorFailedstate. It may or may not be counted depending on the GC. -
Quota doesn’t apply to Pods in the
SucceededorFailedphase. OnlyRunningandPendingPods count. -
The
Terminatingscope counts Pods that are in the process of being deleted (havedeletionTimestampset). UseNotTerminatingto exclude them. -
The
BestEffortscope only counts BestEffort Pods. UseNotBestEffortto count the others. -
The
scopesfield is a list. You can have multiple scopes (e.g.NotTerminatingANDNotBestEffort). All must match for the quota to apply. -
The
podsquota counts Pods regardless of state. A namespace withpods: 100can have 100 Pods in any phase. To count only Running / Pending, use a custom controller. -
Quota doesn’t account for nodes’ overhead. Each node reserves some CPU and memory for the kubelet, system processes, etc. The quota is on the Pod’s resources, not the node’s.
-
The ResourceQuota admission controller is built into the apiserver. It can’t be disabled per-namespace; you have to delete the ResourceQuota.
-
The LimitRange admission controller is also built into the apiserver. Same — delete the LimitRange to disable.
-
A namespace can have a
defaultLimitRange that applies to all objects. Set this up as a default for all new namespaces via an admission webhook or a controller.
See also
- PersistentVolume — the cluster-scoped storage object
- PersistentVolumeClaim — the user-facing storage API
- StorageClass — dynamic provisioning
- Resource Requests and Limits — the per-Pod view
- Storage — the L05 mental model