Skip to content

Namespaces and Resource Quotas

A Namespace divides a single cluster’s objects and names among multiple users, teams, or projects, but it does not divide the network — that takes a NetworkPolicy.

A Namespace scopes object names: Deployment web in namespace team-a and Deployment web in namespace team-b are two completely unrelated objects that happen to share a name. Namespaces are also the unit that RBAC (covered in a later module) is usually scoped to, so a team’s permissions can be limited to the namespace they own rather than the whole cluster.

What a Namespace does not give you is network isolation. By default, a Pod in team-a can still send traffic to a Pod in team-b — namespaces are a naming and organizational boundary, not a network boundary. If you need to stop that traffic, you need a NetworkPolicy, covered in the Networking module.

apiVersion: v1
kind: Namespace
metadata:
name: team-a
Terminal window
kubectl create namespace team-a
kubectl config set-context --current --namespace=team-a

Some objects are cluster-scoped — they exist outside any namespace entirely, because they describe cluster-wide concepts rather than something owned by one team. Nodes, PersistentVolumes, and ClusterRoles are all cluster-scoped. Most everyday objects — Pods, Deployments, Services, ConfigMaps, PersistentVolumeClaims — are namespaced.

Terminal window
# List objects that live outside any namespace
kubectl api-resources --namespaced=false

ResourceQuota: capping a namespace’s total consumption

Section titled “ResourceQuota: capping a namespace’s total consumption”

A ResourceQuota caps the aggregate resource consumption of an entire namespace — total CPU and memory requests and limits across every Pod in it, and/or total object counts such as the maximum number of Pods, Services, or PersistentVolumeClaims.

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

LimitRange: bounding individual Pods and containers

Section titled “LimitRange: bounding individual Pods and containers”

A ResourceQuota caps the namespace as a whole, but says nothing about any single Pod. Without a per-object bound, one unbounded Pod could request enough CPU and memory to consume an entire namespace’s ResourceQuota by itself, starving everyone else in that namespace. A LimitRange closes that gap by setting default, minimum, and maximum requests/limits for individual Pods and containers created in the namespace.

apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 250m
memory: 256Mi
max:
cpu: "2"
memory: 2Gi
min:
cpu: 100m
memory: 128Mi
flowchart LR
  subgraph cluster["Cluster"]
    subgraph nsa["Namespace: team-a"]
      qa["ResourceQuota"] --- la["LimitRange"]
      pa1["Pod"] --- pa2["Pod"]
    end
    subgraph nsb["Namespace: team-b"]
      qb["ResourceQuota"] --- lb["LimitRange"]
      pb1["Pod"] --- pb2["Pod"]
    end
  end
Two namespaces, each bounded by its own ResourceQuota and LimitRange
By default, what do namespaces NOT provide between Pods in different namespaces
Which of these objects is cluster-scoped rather than namespaced
What does a ResourceQuota control that a LimitRange does not
Why does a namespace need a LimitRange in addition to a ResourceQuota