Table of Contents
Kubernetes was designed for efficient resource sharing, but complexity escalates when multiple teams or users step into the same cluster. As organizations scale, the challenge isn't just about running workloads; it's about how those workloads coexist securely and efficiently.
Daniele Polencic from LearnK8s recently broke this down, diving deep into the isolation models, their limitations, and the tooling that makes multi-tenant environments manageable. If you want the full technical breakdown, watch the session.

Kubernetes as a Shared System
To understand multi-tenancy, we must first understand how Kubernetes processes a request. When a user runs `kubectl apply` to create a Deployment, the API Server takes control. It validates the request, runs authentication and authorization checks, and commits the Deployment manifest into etcd.
The Deployment controller inside the `kube-controller-manager` picks up the change, creates a corresponding ReplicaSet, and ensures the desired number of pods exist. The ReplicaSet controller watches for changes, spawns pods accordingly, and registers them in etcd. The kube-scheduler steps in, scanning for unscheduled pods. It evaluates available nodes, selects the best fit, and assigns the pod.
Still, no workloads are running; only metadata exists. The real action begins when the kubelet, running on each worker node, detects a new pod scheduled to its node. It pulls the pod specification from the API server, preps the runtime, and finally launches the containers.
At no point does Kubernetes distinguish between teams or users. Every request passes through the same API server, every resource lands in the same etcd, and every kubelet treats pods the same way.
The reason is Kubernetes is a shared system.
In a multi-tenant cluster, the challenge of this shared infrastructure is that every team's workloads flow through the same control plane.
The API server doesn't care who owns a resource.
The same applies to etcd—there's no inherent separation of data. The scheduler and kubelets don't make distinctions either. When you run `kubectl get deployments`, and you'll see deployments from every team.
But what if you don't want to share?
Introducing Multi-Tenancy in Kubernetes
One approach would be hardcoding tenancy into the API itself, defining scoped endpoints like `/api/team-a` and `/api/team-b`, where each team only sees their resources. Kubernetes achieves this dynamically with Namespaces and RBAC (Role-Based Access Control).
Namespaces create logical boundaries at the API level. When a user in Team A runs `kubectl get pods,` they only see their namespace's pods. In addition, RBAC defines who can access what, ResourceQuotas prevent noisy neighbors from over-consuming shared infrastructure, LimitRanges enforce per-tenant resource constraints, NetworkPolicies segment traffic, and Pod Security Admission restricts unsafe workloads.
But even with all that, Namespaces doesn't isolate workloads. They are just a control mechanism for permissions and API scoping.
Building True Multi-Tenant Platforms
When running a multi-tenant Kubernetes platform, you need all these components working together. You need a framework that expresses tenancy as a single specification like Capsule. Instead of manually configuring quotas, roles, and network policies for every team, Capsule lets you define tenancy in one place.
It's one of the first tools that makes Kubernetes namespaces functional in a multi-tenant environment. Hierarchical Namespace Controller extends namespace capabilities further, while Kubesphere takes a broader platform approach.
However, namespaces have limitations.
Some objects like PersistentVolumes, nodes, Custom Resource Definitions (CRDs), even namespaces themselves aren't bound to a single namespace.
How do you scope them to a specific team? RBAC grants access, but it doesn't partition resources dynamically.
The solution is API proxies.
Tools like Capsule Proxy and KCP sit in front of the real API server as a proxy layer, impersonate users, and filter responses. The control plane remains shared, but tenants only see their own resources. For example, an admin sees all PersistentVolumes, but a tenant only sees their assigned ones. [A team at Apple](https://www.youtube.com/watch?v=dQ4j5V6lqeo) followed a similar API Server as a Service model but took a unique approach by fully abstracting the Kubernetes API server for tenants. Instead of running a single shared API or filtering access via proxies, they create tenant-scoped workspaces where each team interacts with its own virtualized API layer. However, even this approach doesn't solve the CRD isolation problem.
CRDs are tricky; they live in etcd, and etcd is shared. You can't install two versions of the same CRD in a single cluster.
Similarly, you can't create CRD-level isolation without splitting etcd.
Then, there's the problem of node isolation. You can restrict CPU and memory and enforce network policies, but you can't isolate I/O. If a database runs on a node with noisy neighbors, they compete for disk throughput. You can't isolate network bandwidth at the node level, either.
Namespaces weren't designed to give a real multitenancy. And if you're trying to isolate CRDs, you hit the same roadblock—shared control plane, shared etcd, shared infrastructure.
So how do we fix this?
If isolating the database is too complex, isolate the control plane instead.
Instead of running a single control plane for every team, give each tenant a dedicated API server and an isolated etcd instance.
Teams can run different CRD versions without conflicts, workloads are decoupled, and tenancy becomes a first-class concept. The challenge isn't in the idea—it's in the execution.
Achieving Hard Isolation: Control Plane Strategies
There are three major approaches to hard separation at the control plane level, each with its own trade-offs.
The first approach is simple: dedicated clusters for each team. Every team gets its own cluster, fully isolated, with separate control and data planes. However, managing these clusters at scale is a different challenge. You need a way to orchestrate deployments across them, distribute workloads efficiently, and interconnect networking, storage, and I/O.
Tools like KubeAdmiral, Karmada, Sveltos, Kubesphere, and Kubeslice come in here. They solve the problem of multi-cluster workload distribution by ensuring that applications, policies, and networking remain synchronized across independent clusters. Karmada, for instance, deploys a cluster manager that installs control planes and agents in each target cluster and creates an abstraction that ties them together.
The second strategy is nesting control planes inside a single manager cluster.
Instead of running separate clusters, you package the entire Kubernetes control plane as a pod inside an existing cluster.
Like managed Kubernetes services on AWS, GKE, or AKS, you attach worker nodes directly to the control plane. The architecture shifts the burden of worker node management onto the teams using the cluster. They provision their own virtual machines, attach them to their assigned control plane, and run their workloads independently. You have one cluster running multiple encapsulated control planes as pods, with worker nodes dynamically assigned. Nested control planes work well for managed services.
If a node breaks, it's the tenant's problem, as they own the infrastructure they attach. The tools making this possible are Kamaji, HyperShift from Red Hat, vCluster Pro, and Kosmotron from Mirantis.
Take Kamaji, for example. It starts with a management control plane. When a team needs a cluster, you spin up a new pod—inside that pod is a fully functional Kubernetes control plane. The team provisions its nodes, installs kubelet, and attaches them to their new control plane. At that point, they have a fully isolated Kubernetes environment.
If another team needs a cluster, the same pattern repeats: they launch a new control plane pod, attach nodes, and deploy workloads. It's a self-service multi-tenancy model with full API server isolation.
The third approach is having single-cluster control planes without external nodes. Instead of spinning up control planes as pods in an external management cluster, everything stays inside one cluster. The control planes don't have their own nodes; instead, they synchronize resources back to the main cluster.
Understanding vCluster and Multi-Tenancy Tradeoffs
vCluster runs isolated control planes inside a shared cluster, but these control planes don't have nodes. When you deploy a pod inside a vCluster, it won't run—because the scheduler doesn't see it, and the database isn't real.
The vCluster API server only holds the request. Nothing happens until the syncer moves resources from the virtual control plane to the main cluster's API server. The pod gets copied over, the real scheduler picks it up, and it runs on actual nodes.
The same principle applies to global resources. PersistentVolumes exist at the cluster level, meaning all tenants would typically see every PV. But vCluster filters visibility behind the scenes to ensure each tenant only sees their own. It's an illusion—everything is still shared, but it looks fully isolated from the tenant's perspective.
Evaluating Multi-Tenancy Approaches
Multi-tenancy in Kubernetes isn't just about picking a tool but understanding the trade-offs. Every approach has its limits, and the landscape isn't balanced.
Dedicated clusters are the cleanest solution, primarily when operating across multiple clouds or regions. Full isolation, no shared resources, no tenant conflicts. But not every team needs that level of separation, and managing fleets of clusters adds complexity.
Control plane as a service works well for managed Kubernetes providers. Spinning up dedicated control planes per tenant makes sense if you're offering Kubernetes as a service. But unless that's your business model, the use case is limited.
That brings us to the real contenders—Capsule, vCluster, and native Kubernetes namespaces. They don't require fully custom infrastructure, they scale without breaking core Kubernetes workflows, and they offer a practical balance between isolation and efficiency.
Making the Right Tradeoffs
Multi-tenancy isn't a single feature. It's a range of solutions, each trading off isolation, complexity, and cost.
Most teams start with namespaces. It's simple, familiar, and works for basic segmentation. But you need more when you need isolation beyond API boundaries—when teams require their own CRD versions, or when workloads compete for storage, network, or I/O.
Capsule brings structure and control to namespaces. vCluster virtualizes control planes, allowing teams to run different CRDs. If more profound isolation is required, you move to dedicated control planes and eventually separate clusters.
At the far end of the spectrum, you're building custom platforms—integrating networking, storage, and security across multi-cluster or multi-region deployments.
So how do you decide where to stop?
There's no single answer. Each approach comes with tradeoffs.
Kubernetes was designed for sharing. Compute is pooled, workloads coexist, and multi-tenancy is deciding how much isolation you need. Start small—namespaces, quotas, RBAC. Move up when you need stronger guarantees—Capsule, vCluster, KCP. Step into control plane isolation, dedicated clusters, and fully distributed systems if that's not enough.
There's no perfect model—only the right balance for your environment.