Kubernetes multi-tenancy is almost always drawn as a single axis: namespace → vCluster → separate cluster. Cheap and weak on the left, expensive and solid on the right, pick a point that matches your appetite for risk.
The axis is convenient and wrong. vCluster has recently come to occupy two different places on it, and the cost of separate clusters does not grow with their number. The decision breaks down into three questions, and their order is fixed.
Question one: who is the tenant
A namespace is not a security boundary. It is not a virtual machine, the kernel is shared, and a privileged container walks out onto the host no matter how many RBAC roles are hung around it. Hence the first divide: are you protecting against a neighbour's accidental mistake, or against the neighbour?
For in-house teams with mutual trust a namespace does the job, provided it is assembled in full: RBAC without wildcard verbs, NetworkPolicy default-deny (Kubernetes allows all traffic between namespaces by default — that is a hole, not a setting), ResourceQuota together with LimitRange. Together specifically: a quota without a LimitRange means the first pod with no requests eats all of it. The weakest layer sets the strength of the whole construction, so “we will configure NetworkPolicy later” is equivalent to “we will not configure it”.
The same place holds the one change in years that genuinely moves the trust boundary. In Kubernetes 1.36 user namespaces reached stable: hostUsers: false maps root inside the container to an unprivileged uid on the host, and a container escape stops being root on the node. The gate's path: alpha in 1.28, beta from 1.30, beta on by default from 1.33, stable from 1.36. Worth keeping in mind that this is a pod-level option, not a cluster property: GA means “safe to rely on”, not “already applied to your workloads”.
Question two: does the tenant need cluster-scoped access
If a team needs its own CRDs, its own namespaces or cluster-admin within its perimeter, no RBAC configuration will make a namespace fit. This is not a question of trust but of API scope. This is where vCluster starts: the tenant gets its own API server while workloads are synced into the host cluster.
Over the past year that picture stopped being complete. vCluster gained private nodes — the tenant cluster's own worker nodes, which can live in a different VPC, at a different provider or on bare metal, attached to the control plane over a VPN. Isolation is no longer only about the control plane, and the “weaker to stronger” axis has split: vCluster without private nodes and vCluster with them are two different answers.
Next comes the part worth costing out before the pilot rather than after. Capabilities are spread across tiers, and the boundaries do not run where you would expect:
- OSS (Apache 2.0) — dedicated control planes, resource syncing, several backing stores. No license required, no connectivity to an external Platform required.
- Free — free of charge and no credit card, but requires connecting to the vCluster Platform for license validation. It covers embedded etcd, private nodes, custom resource syncing, sync patches and the HostPath Mapper.
- Enterprise (Dev / Prod / Scale) — sleep mode, external databases, SSO, audit logs, FIPS and air-gapped delivery.
The consequence is sharp: an isolated environment gets the OSS tier only, which means without private nodes. An organisation that chose vCluster for dedicated nodes and cannot phone home for validation will discover this during rollout. One long-held detail also needs correcting: since version 0.20 the default distribution of the virtual control plane is vanilla k8s rather than k3s, and support for EKS as a distribution was removed at the same time.
Question three: what a mistake costs
The standard argument against a cluster per team is the multiplication of the fixed fee. On EKS that is $0.10 per hour per cluster, about $73 a month, and thirty clusters come to roughly $2,200 a month for control planes alone, before a single workload.
Multiplication is not the expensive part. Once standard support for a version ends, a cluster automatically moves to extended support at $0.60 per hour — six times more. A fleet of separate clusters grows expensive in proportion not to the number of teams but to the number of teams that fail to keep up with upgrades. That inverts the familiar arithmetic: the “cluster per tenant” model costs not $73 × N but $73 × N plus a penalty on organisational discipline, which a growing fleet usually lacks. Spreading that money across tenants is what showback is for — OpenCost and Kubecost count by namespace labels, so labels get attached when the namespace is created, not retroactively.
The decision table
| Situation | Model | What you accept |
|---|---|---|
| In-house teams, trust present, no cluster-scoped need | Namespace + RBAC + default-deny + Quota/LimitRange | A namespace is not a security boundary; strength equals the weakest layer |
| Own CRDs and cluster-admin needed, environment not isolated | vCluster OSS | Workloads run in the host cluster; the control plane is isolated, the workers are not |
| Dedicated nodes needed per tenant | vCluster + private nodes | The Free tier and constant Platform connectivity for license validation |
| Isolated environment, air-gapped | vCluster OSS or separate clusters | Private nodes and air-gapped delivery are absent from OSS |
| Untrusted code, PCI-DSS, HIPAA | Separate clusters | $73/month per control plane, and $0.60/hour on extended support |
The untrusted-code row allows a softer reading: gVisor or Kata through RuntimeClass give pod-level isolation inside a shared cluster, at the price of performance. That does not replace a separate cluster where a regulator demands separation, but it works as a middle option when the requirement comes from common sense rather than from an auditor.
What not to pick up in 2026
The Hierarchical Namespace Controller with its kubectl hns shows up in every other multi-tenancy round-up. The repository moved to the kubernetes-retired organisation and was archived, its last commit dates to April 2025, and no successor has been named. Building a namespace hierarchy on it now means scheduling a migration.
The “tenant as an object, quotas and policies across a set of namespaces” scenario is covered by Capsule — a CNCF project, alive (v0.14.3 shipped on 31 August 2026), API group capsule.clastix.io/v1beta2, plus the global quotas that have appeared on top of several tenants. This is neither a migration from HNC nor a feature-for-feature replacement: it is a different model where the root object is a Tenant rather than a tree of namespaces.
Two planes that get confused regularly deserve separating. Argo CD's AppProject constrains who deploys what and where, and that is a delivery boundary. It replaces neither ResourceQuota, nor NetworkPolicy, nor Pod Security Admission inside the tenant's namespace. A configured AppProject over an empty namespace perimeter gives the feeling of isolation without isolation. Admission-level policy is a separate layer, and the network perimeter is easier to build on Cilium with DNS-based egress and L7 rules.
An order, not a scale
The three questions come in a fixed order. Who the tenant is decides whether a namespace fits at all. Whether the tenant needs cluster-scoped access decides whether a virtual control plane is needed. Only then is the price computed, because it depends on the first two answers and on how quickly the organisation rolls out upgrades.
The answers to the first two questions are already known today; they need no research. The third changes over time — and it changes for the worse precisely for those who picked separate clusters in order to avoid thinking about isolation.