A LimitRange bounds one container. A ResourceQuota bounds the sum for the whole namespace: how many Pods, how much CPU requested in total, how much memory limited in total.
A quota
apiVersion: v1
kind: ResourceQuota
metadata:
name: market-quota
spec:
hard:
pods: "4"
requests.cpu: "1"
limits.memory: 2Gikubectl create quota market-quota --hard=pods=4,requests.cpu=1,limits.memory=2Gi
kubectl describe quota market-quotaResource Used Hard
-------- ---- ----
limits.memory 384Mi 2Gi
pods 3 4
requests.cpu 300m 1Used is kept up to date by the cluster; Hard is what you set.
Two kinds of refusal
exceeded quota: market-quota, requested: pods=1, used: pods=4, limited: pods=4must specify requests.cpu for: web, when a counted resource is missing from a containerThe second one surprises people. Once a quota counts requests.cpu, every container in the namespace must have a CPU request, or the Pod is refused. The usual fix is a LimitRange with defaults in the same namespace, so plain Pods pass.
Where it shows
A refused kubectl run prints the error. A refused Deployment does not; its ReplicaSet does:
NAME READY UP-TO-DATE AVAILABLE
market-api 2/3 2 2
kubectl describe rs market-api-7b657d5fd6
Warning FailedCreate (x6 over 2m) Error creating: pods "market-api-7b657d5fd6-x9k2p" is forbidden: exceeded quota: …The controller retries with a growing backoff. Raise the quota or free something, and the missing Pod appears on the next try.