The article on requests and limits explains how a correctly sized pod behaves. Nothing in that mechanic stops a team from deploying a thousand of them, each perfectly sized individually, until the entire cluster’s capacity is exhausted at every other team’s expense. ResourceQuota and LimitRange answer a different question: not “is this pod correctly sized” but “how much is an entire namespace allowed to consume.”

ResourceQuota: an aggregate cap per namespace

A ResourceQuota caps the sum of resources requested or consumed by every object in a namespace, not a single object.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-payments-quota
  namespace: payments
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    pods: "50"

Once that quota is in place, every new pod created in the payments namespace has to declare explicit requests: without that declaration, the object’s creation is rejected outright by the API server, not just flagged. That’s a side effect often discovered by surprise: setting a ResourceQuota on a namespace where pods were already running without explicit requests blocks any new deployment until every pod gets fixed.

LimitRange: defaults and bounds

Where ResourceQuota caps an aggregate, LimitRange acts pod by pod, container by container, at creation time: it injects default values into what doesn’t declare any, and rejects whatever exceeds an individual ceiling.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: payments
spec:
  limits:
    - default:
        cpu: "500m"
        memory: 512Mi
      defaultRequest:
        cpu: "250m"
        memory: 256Mi
      max:
        cpu: "2"
        memory: 2Gi
      type: Container

This LimitRange solves exactly the trap mentioned above: a pod created without explicit requests automatically gets 250m/256Mi, satisfying the ResourceQuota requirement without the developer having to think about it. The two mechanisms combine naturally: LimitRange fills individual gaps, ResourceQuota caps the resulting aggregate.

The trap of a ceiling never revisited

A ResourceQuota set once at namespace launch and never reconsidered becomes either an artificial ceiling blocking legitimate team growth, or a limit so generous it protects nothing anymore. The quota needs the same discipline as any budget: revisited periodically against actual observed usage (kubectl describe resourcequota shows current consumption against the cap), not set once and forgotten.

These two mechanisms are the technical counterpart to the isolation described in the article on GitOps at scale: an AppProject restricts which namespaces a team can target, ResourceQuota and LimitRange restrict what it can consume there once deployment is authorized. Scope isolation without a consumption ceiling still lets a legitimately authorized team exhaust the whole cluster’s shared capacity.

Takeaway

ResourceQuota caps a namespace’s aggregate consumption, LimitRange injects default values and bounds each container individually, and the two combine to keep a missed requests declaration from becoming either a creation-time rejection or unchecked consumption. Setting this per-namespace governance, with periodic review, is part of the multi-team foundation of a Kubernetes migration that grows beyond a single application.