Namespace Resource Quotas
SummaryCovers ResourceQuota creation via imperative commands and YAML,...
Covers ResourceQuota creation via imperative commands and YAML,...
Covers ResourceQuota creation via imperative commands and YAML, compute quotas (CPU, memory requests/limits), object count quotas (pods, services, configmaps, secrets), the enforcement rule that forces Pods to specify resources when quotas are active, inspection with kubectl describe quota, and interaction with LimitRanges.
Namespace Resource Quotas
A ResourceQuota is a namespaced object that constrains the aggregate resource consumption within that namespace. Once a quota is active, the API server tracks the total resources requested by all Pods in the namespace and rejects any new Pod that would cause the total to exceed the quota.
Think of a ResourceQuota as a budget: the namespace has a fixed allocation of CPU, memory, and object counts. Every Pod spends from that budget. When the budget is exhausted, no more Pods can be created until existing ones are deleted or the quota is increased.
Creating a ResourceQuota
Imperative Command
The fastest approach on the exam:
kubectl create quota my-quota \
--hard=pods=10,cpu=4,memory=8Gi \
-n dev
This creates a ResourceQuota named my-quota in the dev namespace with three constraints:
- Maximum 10 Pods
- Maximum 4 CPU cores total (across all Pods’ requests)
- Maximum 8 GiB memory total (across all Pods’ requests)
Verify:
kubectl describe quota my-quota -n dev
Name: my-quota
Namespace: dev
Resource Used Hard
-------- ---- ----
cpu 0 4
memory 0 8Gi
pods 0 10
The Used column shows current consumption. The Hard column shows the ceiling. As Pods are created, Used increases.
Declarative YAML
For more complex quotas, a YAML manifest gives full control:
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
This quota distinguishes between requests and limits:
- requests.cpu: “4” — total CPU requests across all Pods cannot exceed 4 cores
- limits.cpu: “8” — total CPU limits across all Pods cannot exceed 8 cores
- requests.memory: 8Gi — total memory requests cannot exceed 8 GiB
- limits.memory: 16Gi — total memory limits cannot exceed 16 GiB
The distinction matters. A Pod requesting 500m CPU with a limit of 1 CPU consumes 500m from the requests budget and 1 from the limits budget. Quotas on both prevent overcommitment (limits exceed node capacity) and over-request (requests consume too much guaranteed capacity).
Compute Resource Quotas
The following compute resources can be constrained:
| Quota Field | Description |
|---|---|
requests.cpu | Total CPU requests across all Pods |
requests.memory | Total memory requests across all Pods |
limits.cpu | Total CPU limits across all Pods |
limits.memory | Total memory limits across all Pods |
cpu | Alias for requests.cpu |
memory | Alias for requests.memory |
CPU is measured in cores (or millicores: 500m = 0.5 cores). Memory is measured in bytes with standard suffixes: Ki, Mi, Gi, Ti.
Example: Tracking Resource Consumption
# Create namespace and quota
kubectl create namespace quota-lab
kubectl create quota compute-quota \
--hard=requests.cpu=2,requests.memory=4Gi,limits.cpu=4,limits.memory=8Gi \
-n quota-lab
# Create a Pod that consumes resources
kubectl run web --image=nginx:1.25 \
--requests='cpu=250m,memory=256Mi' \
--limits='cpu=500m,memory=512Mi' \
-n quota-lab
# Check quota usage
kubectl describe quota compute-quota -n quota-lab
Name: compute-quota
Namespace: quota-lab
Resource Used Hard
-------- ---- ----
limits.cpu 500m 4
limits.memory 512Mi 8Gi
requests.cpu 250m 2
requests.memory 256Mi 4Gi
One Pod consumed 250m/2000m of the CPU request budget and 256Mi/4096Mi of the memory request budget. The remaining budget is available for additional Pods.
Object Count Quotas
ResourceQuotas also limit the number of API objects:
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota
namespace: dev
spec:
hard:
pods: "20"
services: "10"
services.loadbalancers: "2"
services.nodeports: "5"
configmaps: "20"
secrets: "20"
persistentvolumeclaims: "10"
replicationcontrollers: "10"
Each field caps the total count of that object type in the namespace. Attempting to create the 21st Pod in a namespace with pods: 20 produces an error:
Error from server (Forbidden): pods "pod-21" is forbidden:
exceeded quota: object-quota, requested: pods=1, used: pods=20, limited: pods=20
Common object count fields:
| Quota Field | Object Type |
|---|---|
pods | Total Pods |
services | Total Services |
services.loadbalancers | LoadBalancer Services only |
services.nodeports | NodePort Services only |
configmaps | Total ConfigMaps |
secrets | Total Secrets |
persistentvolumeclaims | Total PVCs |
count/deployments.apps | Total Deployments |
The count/<resource>.<group> syntax works for any resource, including custom resources:
spec:
hard:
count/deployments.apps: "5"
count/jobs.batch: "10"
count/cronjobs.batch: "3"
The Enforcement Rule: Pods Must Specify Resources
This is the most commonly encountered gotcha with ResourceQuotas. When a namespace has a compute quota (any of requests.cpu, requests.memory, limits.cpu, limits.memory), every Pod in that namespace must specify the corresponding resource field.
If a quota sets requests.cpu, every Pod must include resources.requests.cpu. If a quota sets limits.memory, every Pod must include resources.limits.memory. A Pod without the required field is rejected immediately:
Error from server (Forbidden): pods "no-resources" is forbidden:
failed quota: compute-quota: must specify limits.cpu, limits.memory,
requests.cpu, requests.memory
This means existing workflows that never specified resource requests or limits break the moment a quota is applied. The solution is one of two approaches:
- Add resource specifications to every Pod/Deployment in the namespace. This is the correct long-term approach.
- Create a LimitRange that provides defaults. When a LimitRange with
defaultanddefaultRequestvalues exists, Pods that omit resource specifications inherit the defaults. The next section covers LimitRanges in detail.
In practice, teams deploy a LimitRange alongside the ResourceQuota to ensure no Pod is rejected solely for missing resource specifications.
Combining Compute and Object Quotas
A single ResourceQuota can contain both compute and object constraints:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
# Compute
requests.cpu: "8"
requests.memory: 16Gi
limits.cpu: "16"
limits.memory: 32Gi
# Object counts
pods: "50"
services: "20"
configmaps: "30"
secrets: "30"
persistentvolumeclaims: "15"
You can also create multiple ResourceQuota objects in the same namespace. Kubernetes merges them — a Pod must satisfy all quotas simultaneously. If quota-a allows 10 Pods and quota-b allows 5, the effective limit is 5 (the more restrictive quota wins).
Quota Scopes
Quotas can be scoped to specific Pod categories:
apiVersion: v1
kind: ResourceQuota
metadata:
name: besteffort-quota
namespace: dev
spec:
hard:
pods: "5"
scopes:
- BestEffort
This quota limits only BestEffort Pods (those without any resource requests or limits) to 5. Pods with resource specifications are not affected by this quota.
Available scopes:
| Scope | Applies To |
|---|---|
BestEffort | Pods with no resource requests or limits |
NotBestEffort | Pods with at least one resource request or limit |
Terminating | Pods with activeDeadlineSeconds set |
NotTerminating | Pods without activeDeadlineSeconds |
Inspecting Quotas
Describe a Specific Quota
kubectl describe quota my-quota -n dev
Shows the quota name, namespace, each resource field with its current Used value and Hard limit.
List All Quotas in a Namespace
kubectl get resourcequota -n dev
NAME AGE REQUEST LIMIT
compute-quota 5m requests.cpu: 250m/2, requests.memory: 256Mi/4Gi limits.cpu: 500m/4, limits.memory: 512Mi/8Gi
object-quota 5m configmaps: 3/20, pods: 1/20, secrets: 2/20, ...
Check Why a Pod Was Rejected
If a Pod creation fails due to quota, the error message specifies exactly which resource was exceeded:
kubectl run overflow --image=nginx --requests='cpu=10' -n quota-lab
Error from server (Forbidden): pods "overflow" is forbidden:
exceeded quota: compute-quota, requested: requests.cpu=10,
used: requests.cpu=250m, limited: requests.cpu=2
The error tells you: the Pod requested 10 CPU cores, the quota allows 2 total, and 250m is already used. This diagnostic output is precise enough to identify the problem immediately.
Exam Strategy
ResourceQuota tasks on the CKAD are straightforward:
- Create the quota:
kubectl create quota <name> --hard=<key>=<value>,... -n <ns> - Verify the quota:
kubectl describe quota <name> -n <ns> - Understand the enforcement rule: adding a compute quota forces all Pods to specify resources.
- Diagnose failures: read the error message — it tells you exactly which resource was exceeded.
The imperative kubectl create quota command handles the most common exam scenarios. For complex quotas with separate request and limit fields, write a YAML manifest.