Multi-tenancy is a spectrum of isolation, not a single choice. The right level depends on how much control each tenant needs and how much separation the business requires, and most platforms use more than one level at once.
Isolation
▲
│ Dedicated cluster regulated data, separate versions, own blast radius
│ Virtual cluster own CRDs, operators and admin rights on shared nodes
│ Tenant self-service namespaces within a team's quota
│ Namespace one per application and environment, e.g. payments-prod
└──────────────────────────────────────────────────────▶ Cost and operational effort
Tenant definition (Git) ─▶ GitOps ─▶ namespaces, RBAC, quotas, network and admission policy
Key design decisions
- Isolation per workload, not per platform: namespaces per application and environment by default; a tenant layer where teams need self-service; virtual clusters when teams need cluster-scoped resources; dedicated clusters only for regulatory separation, different Kubernetes versions or distinct scaling profiles such as GPU workloads.
- Onboarding as code: one tenant definition creates namespaces, group-based RBAC, quotas and limit ranges, network policies and admission policies, so every tenant starts secure and consistent.
- Data-plane isolation on shared nodes: default-deny networking, dedicated node pools or taints for sensitive and GPU workloads, and sandboxed runtimes where the risk justifies it.
- Golden paths: templates for a service, its pipeline and its dashboards, so the secure default is also the easiest option.
- Cost attribution: tenant, application and cost-centre labels from day one, so spend can be shown back to the business.