🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

What is Multi-tenancy in Kubernetes Explained Simply

Multi-tenancy in Kubernetes lets multiple teams share one cluster safely. Learn namespace-based tenancy, vCluster, RBAC, network policies, and when to go single vs multi-tenant.

DevOpsBoysJun 5, 20263 min read
Share:Tweet

Multi-tenancy in Kubernetes means multiple teams, projects, or customers share the same cluster without stepping on each other's toes. Get it right and you save cost. Get it wrong and one team can crash another's workloads.


The Core Problem

By default, Kubernetes has no concept of isolation between tenants. Pod A in namespace team-a can talk to Pod B in namespace team-b. One misconfigured resource limit can steal all cluster CPU. Multi-tenancy is the set of patterns that prevents this.


Types of Multi-tenancy

1. Namespace-based Tenancy (Soft)

Each team gets their own namespace. RBAC controls who can do what. Network policies block cross-namespace traffic.

Pros: Simple, built-in
Cons: Shared control plane, shared nodes — not true isolation

2. Virtual Clusters (Medium)

Tools like vCluster create a full Kubernetes API server per tenant, running as pods inside the host cluster.

Pros: Near-complete isolation, tenant can install CRDs freely
Cons: More overhead than namespaces

3. Separate Clusters (Hard Tenancy)

One cluster per tenant. Full isolation, separate billing.

Pros: True isolation
Cons: High cost, complex fleet management


Setting Up Namespace-based Tenancy

Step 1 — Create namespace per team

bash
kubectl create namespace team-alpha
kubectl create namespace team-beta

Step 2 — RBAC per namespace

yaml
# team-alpha-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: team-alpha
  name: team-alpha-developer
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "deployments", "services", "configmaps", "jobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-alpha-binding
  namespace: team-alpha
subjects:
- kind: Group
  name: team-alpha-devs
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: team-alpha-developer
  apiGroup: rbac.authorization.k8s.io

Step 3 — Resource quotas

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"
    services: "10"
    persistentvolumeclaims: "5"

Step 4 — LimitRange (prevents resource-hogging pods)

yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: team-alpha-limits
  namespace: team-alpha
spec:
  limits:
  - type: Container
    default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    max:
      cpu: "2"
      memory: 4Gi

Step 5 — Network policy (block cross-namespace traffic)

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-namespace
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector: {}  # only from same namespace
  egress:
  - to:
    - podSelector: {}  # only to same namespace
  - ports:
    - port: 53           # allow DNS
      protocol: UDP

vCluster Setup (Virtual Clusters)

bash
# Install vcluster CLI
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster && mv vcluster /usr/local/bin
 
# Create virtual cluster for team-alpha
vcluster create team-alpha --namespace vcluster-team-alpha
 
# Connect to virtual cluster
vcluster connect team-alpha --namespace vcluster-team-alpha

Inside the vCluster, the team sees a full Kubernetes API — they can create CRDs, install operators, and manage their own resources without affecting other tenants.


Common Multi-tenancy Issues

Issue: Teams bypassing network policies

Fix: Use a CNI that enforces NetworkPolicy strictly (Cilium, Calico). Flannel does NOT enforce NetworkPolicy.

Issue: Node-level isolation

Namespace isolation doesn't prevent pods from reaching node metadata APIs. Fix with:

yaml
# Block AWS IMDS access
- ports:
  - port: 80
  to:
  - ipBlock:
      cidr: 0.0.0.0/0
      except:
      - 169.254.169.254/32  # AWS metadata service

Issue: Shared storage class leaking data

Use per-tenant StorageClasses with encryption enabled and separate backend buckets.


Choosing the Right Model

RequirementNamespacevClusterSeparate Cluster
Dev/test environments❌ too expensive
Separate CRDs per team
SaaS customer isolation
Regulatory compliance⚠️
Cost efficiency✅✅

Tools Worth Using

Start with namespaces + RBAC + ResourceQuota for 80% of use cases. Move to vCluster when teams need their own CRDs or cluster-admin access.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments