ResourceQuota and LimitRange

The Deployment is one replica short and kubectl get pods has nothing to show for it, so where did that Pod go? A ResourceQuota caps what a single namespace may request in total and is checked at admission, so the Pod is refused before it exists and the 403 lands on the ReplicaSet that asked for it, as a FailedCreate event and a ReplicaFailure condition. A LimitRange is the other half, because it supplies the request a quota demands from every Pod that names none.

Play the animation 5 steps, animated, best on a wide screen

ResourceQuota and LimitRange, Kubernetes diagram

ResourceQuota and LimitRange, step by step

  1. The Pod template names no cpu at all, so LimitRanger rewrites it here, in the one phase where the object can still be changed, and sets defaultRequest.cpu 500m. That injection is structural rather than convenient: once a quota constrains requests.cpu, a Pod naming neither requests nor limits is a Pod the quota cannot count.

    Play from step 1
  2. LimitRanger is back in the validating phase, and this time it may only refuse. It checks the request it just injected against min, max and maxLimitRequestRatio, so one plugin sits at two positions in the chain and does a different job at each.

    Play from step 2
  3. Validating webhooks and ValidatingAdmissionPolicy get their say next, calling out over HTTPS or running in process. None of them may mutate the object any more, and a single deny ends the request before the quota is ever consulted. The Admission Chain card owns this stage.

    Play from step 3
  4. ResourceQuota runs after all of them. The field spec.hard is the ceiling and status.used is the running sum, so web-1 fits because 0 plus 500m is inside requests.cpu 1, and admission itself adds that 500m to used. Pod web-2 lands the sum exactly on the ceiling. Pod web-3 would take it to 1.5, so admission answers 403 with exceeded quota.

    Play from step 4
  5. Only what admission passed is written. Two Pod objects reach ETCD and kubectl get pods -n team-a lists them, and there is no third object to list or to describe. The ReplicaSet asked for it, so the ReplicaSet is what hears the refusal, as a FailedCreate event and a ReplicaFailure condition.

    Play from step 5

Sources