How Multi-Tenancy Works in a Cluster
Summary
- Definition: Multi-tenancy in Kubernetes is running workloads from multiple teams, apps, or environments on one shared cluster while keeping them isolated by namespace, RBAC, quota, and network policy.
- Insight: Kubernetes has no first-class "tenant" object. A tenant is a convention you assemble from namespaces plus the policies bound to them.
- Key Concepts: The building blocks are Namespace (scope), RBAC (who can act), ResourceQuota / LimitRange (how much), NetworkPolicy (who can talk), and Pod Security Standards (what a pod may do).
- When to Use: Consolidating many small teams or services onto shared nodes for cost and operational efficiency, where soft isolation between trusted-ish tenants is acceptable.
- Limitations/Trade-offs: The node kernel is shared, so namespace isolation is a soft boundary, not a security boundary against a hostile tenant. Hard isolation needs separate clusters or virtualization.
- Related Topics: Namespace design, resource quotas, network policy defaults, and blast-radius planning.
Foundations
Multi-tenancy is a packing problem with a safety constraint.
You want many workloads on shared infrastructure to save money and reduce operational sprawl. You also want a failure or abuse in one tenant to stay contained.
Kubernetes gives you a namespace as the primary unit of grouping. Most namespaced objects - Deployments, Services, ConfigMaps, Secrets, PVCs - live inside exactly one namespace.
A namespace by itself is only a name scope. It does not isolate anything until you attach policy to it.
That is the mental model to hold: a tenant equals a namespace (or a set of namespaces) plus the RBAC, quota, and network rules bound to that namespace.
There are two broad flavors of tenancy. Soft multi-tenancy assumes tenants are cooperative internal teams; you defend against mistakes and accidents. Hard multi-tenancy assumes tenants may be adversarial and requires stronger boundaries.
Vanilla Kubernetes is designed for soft multi-tenancy out of the box. Pushing toward hard isolation on a shared cluster means adding node isolation, stricter runtimes, and policy enforcement on top.
Mechanics & Interactions
Isolation is layered. Each layer answers a different question.
Naming and scope. The namespace partitions the API. Two teams can both own a Deployment named api without collision because the objects are team-a/api and team-b/api.
Identity and authorization. RBAC decides who may act inside a namespace. A Role grants verbs on resources within one namespace; a RoleBinding grants that Role to a user, group, or ServiceAccount.
Cluster-scoped power lives in ClusterRole and ClusterRoleBinding. A common pattern is one shared ClusterRole bound per-namespace with RoleBindings, so each team gets identical rights scoped to their own namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-a-admins
namespace: team-a
subjects:
- kind: Group
name: team-a
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-admin
apiGroup: rbac.authorization.k8s.ioConsumption limits. A ResourceQuota caps aggregate CPU, memory, storage, and object counts per namespace. A LimitRange sets per-Pod or per-Container defaults and ceilings so tenants cannot submit unbounded pods.
Together these stop one tenant from consuming the whole cluster and starving the rest.
Network reachability. By default every pod can reach every other pod across all namespaces. A NetworkPolicy (enforced by the CNI plugin) changes that.
The standard move is a default-deny ingress policy per namespace, then explicit allow rules. Without a policy-enforcing CNI, NetworkPolicy objects are silently ignored.
Runtime privilege. Pod Security Standards, applied via the built-in Pod Security admission controller, restrict what a pod may do - running as non-root, dropping capabilities, disallowing host namespaces. The restricted profile is the target for untrusted tenants.
Node runtime reality. All of these pods ultimately run on shared nodes through containerd via the CRI. They share the host kernel. This is why namespace boundaries are administrative, not a hard security wall.
Advanced Considerations & Applications
Blast-radius thinking is what turns these primitives into a real tenancy design.
Ask: if tenant X misbehaves - a crash loop, a memory leak, a runaway for loop, a compromised container - what else is affected?
Quotas and limits contain resource blast radius. A tenant that hits its CPU quota throttles itself, not its neighbor.
PriorityClass and Quality of Service classes decide who gets evicted first under node pressure. Give platform-critical workloads higher priority so tenant overcommit does not take down ingress or DNS.
For workloads you cannot trust to share a kernel, isolate at the node level. Use taints, tolerations, and nodeSelector/affinity to pin tenants onto dedicated node pools.
For stronger isolation still, sandboxed runtimes like gVisor or Kata Containers add a per-pod boundary, and separate clusters remain the strongest answer.
Automation matters at scale. Tools like Hierarchical Namespace Controller or the vcluster / Capsule projects let you template a tenant - namespace plus quota plus RBAC plus default policies - as one unit, so onboarding a new team is repeatable and GitOps-friendly.
Common Misconceptions
"A namespace is a security boundary." It is an administrative and policy boundary. Real isolation comes from the RBAC, network, quota, and runtime policies you attach - and even then the kernel is shared.
"Pods in different namespaces can't talk to each other." They can, freely, until a NetworkPolicy (and a CNI that enforces it) says otherwise.
"ResourceQuota limits how much a single pod uses." No - quota caps the namespace total. Per-pod defaults and ceilings come from LimitRange.
"Multi-tenancy means one big cluster is always cheapest." Consolidation saves on nodes and ops, but past a point the isolation engineering and blast-radius risk make multiple clusters the better trade.
"Docker isolates the tenants." Docker builds and runs images in dev; on cluster nodes it is containerd via the CRI that runs the pods. Tenancy isolation is a Kubernetes-layer concern.
FAQs
Is one cluster per team or one shared cluster better? Shared clusters win on cost and operational overhead; per-team clusters win on isolation and blast-radius. Most orgs run a small number of shared multi-tenant clusters and split out only the workloads that truly need hard isolation.
Can Kubernetes give me true hard multi-tenancy alone? Not by itself. You add node pools, sandboxed runtimes, strict Pod Security, and policy engines. For genuinely hostile tenants, separate clusters remain the safest option.
What is the minimum viable tenant setup? A namespace, a RoleBinding scoping team access, a ResourceQuota, a LimitRange, and a default-deny NetworkPolicy.
Do NetworkPolicies work everywhere? Only if your CNI enforces them (Calico, Cilium, and others do). On a CNI without enforcement, the objects apply but have no effect.
Where do Secrets fit in tenancy? Secrets are namespaced, so RBAC on Secrets is per-namespace. Restrict get/list on Secrets tightly, since broad read access undermines tenant isolation.
Related
- Tenancy Basics
- Environment Separation
- Resource Quotas & LimitRanges
- Noisy Neighbor Controls
- Tenancy Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).