在宿主集群的命名空间里跑一套完整的 Kubernetes 控制面,给租户一个「自己的集群」
vcluster 由 Loft Labs 开源(Apache-2.0),当前最新版本为 v0.37.1(2026-09-14),项目活跃。它的核心思路是:在每个租户的命名空间里运行一个轻量的 Kubernetes 控制面(默认是 k3s 发行版),租户拿到的 kubeconfig 指向这个虚拟控制面,可以自己建 CRD、自己管 RBAC、自己装 Operator,而工作负载最终仍然跑在宿主集群的节点上。
它常被拿来与「命名空间 + RBAC + ResourceQuota」比较,差别在于 API 层面:
方案 独立 API Server 独立 CRD 独立 RBAC 独立集群级资源 计算隔离
命名空间多租户 否 否 部分 否 无
vcluster 是 是 是 是(虚拟集群内可见) 无
独立集群 是 是 是 是 有
也就是说,vcluster 把API 层面的隔离做到了接近独立集群的程度,但没有增加计算与内核层面的隔离。这个边界必须讲清楚,否则容易高估它的安全性。
Loft Labs 另有商业产品 vCluster Platform(多集群管理、SSO、策略),开源 chart 与它是两回事,本文只讲开源部分。
CLI 负责创建、连接与切换上下文,底层是 Helm:
# 安装 CLI(macOS 示例)
brew install loft-sh/tap/vcluster
vcluster version
# 创建一个虚拟集群(会自动创建命名空间并连接进去)
vcluster create my-vcluster --namespace team-a
# 创建的等价 Helm 方式
helm repo add loft-sh https://charts.loft.sh
helm repo update
helm install my-vcluster loft-sh/vcluster --namespace team-a --create-namespace
常用子命令:
vcluster create <name> 创建虚拟集群(--connect 默认 true,创建后自动连接)
vcluster connect <name> 切换到虚拟集群的 kube context(vcluster_<name>)
vcluster disconnect 切回宿主集群 context
vcluster list 列出当前 kubeconfig 里可见的虚拟集群
vcluster delete <name> 删除虚拟集群
创建后可用的关键 flag:
--namespace <ns> 宿主集群中的命名空间
--distro k3s|k0s|k8s 虚拟控制面的发行版,默认 k3s
--chart-name / --chart-repo 指定 chart 名称与仓库
--chart-version 锁定 chart 版本(生产环境建议显式锁定)
-f values.yaml 传入自定义 values
--expose 为虚拟控制面创建 LoadBalancer 以暴露端点
--isolate 让工作负载调度与宿主隔离(配合节点选择器)
控制面 Pod 每个 vcluster 一个 StatefulSet,里面跑 API Server、控制器、syncer
backingStore 默认 sqlite 存在容器内,可换成外置 etcd(生产建议)
syncer 常驻进程,负责把资源在虚拟集群与宿主命名空间之间双向同步
CoreDNS 每个虚拟集群自带一套 DNS,解析的是虚拟集群内的服务名
虚拟集群的 API Server 是真正独立的(k3s 嵌入的 apiserver),因此:
kubectl get crd 在虚拟集群里能看到/创建自己的 CRD
kubectl get clusterrole 虚拟集群内的集群级资源只存在于虚拟集群
kubectl get nodes 会看到虚拟节点(除非开启 private nodes)
这是 vcluster 最需要先搞清楚的一节。虚拟集群里创建的多数资源不是自动落到宿主集群的,要由 syncer 按配置同步。
默认开启的同步(sync.toHost,虚拟 → 宿主):
services 虚拟集群的 Service 会在宿主命名空间创建对应资源
endpoints / endpointSlices
persistentVolumeClaims PVC 落到宿主,由宿主 StorageClass 供给
configMaps all: false,只同步被挂载用到的那部分
secrets all: false,同上
pods 核心:Pod 被同步到宿主命名空间并真正调度到宿主节点
默认关闭的同步(sync.toHost,需要显式打开):
ingresses 虚拟集群里的 Ingress 默认不会在宿主生效
gatewayApi HTTPRoute / Gateway / TLSRoute 等
networkPolicies 虚拟集群里写的 NetworkPolicy 默认不生效
serviceAccounts
storageClasses
persistentVolumes
podDisruptionBudgets
priorityClasses
namespaces
volumeSnapshots / volumeSnapshotContents
resourceClaims / resourceClaimTemplates
宿主 → 虚拟(sync.fromHost)的默认值:
events: true
storageClasses / csiDrivers / csiNodes / csiStorageCapacities: auto
(开启虚拟调度器时自动启用)
nodes / secrets / configMaps / ingressClasses / gatewayClasses /
runtimeClasses / priorityClasses: false
自定义资源(CRD 的实例)也不在默认同步范围内,需要逐条声明:
sync:
toHost:
customResources:
certificates.cert-manager.io:
enabled: true
certificaterequests.cert-manager.io/v1: # 可指定版本,不写则用 storage version
enabled: true
关于自定义资源同步的硬约束:
1. 对应的 CRD 必须已经存在于宿主集群,vcluster 会把它复制进虚拟集群
2. 只支持命名空间级资源,集群级资源不支持
3. 同一个 CRD 只能指定一个版本,写多个会导致虚拟集群启动失败
4. 开关的生效时机是控制面重启/滚动,不是热生效
5. 同一个资源类型不能同时配置 toHost 与 fromHost
vcluster 有几种部署形态:
共享节点(默认) Pod 调度到宿主集群的共享节点上,隔离靠 API 层
privateNodes 为租户准备专属节点(vcluster 会模拟节点对象),计算层也隔离
Standalone 不需要宿主集群,直接把控制面部署在裸机/虚拟机上(自 v0.29 起)
Standalone 的最小配置:
controlPlane:
standalone:
enabled: true
joinNode:
enabled: true
privateNodes:
enabled: true
共享节点形态下的隔离边界,可以用一句话概括:虚拟化的是 API,不是内核。
sync.toHost.customResources。networkPolicies 默认不同步,意味着虚拟集群里写的 NetworkPolicy 默认不生效。租户以为已经做了隔离,实际上没有。需要网络隔离时要么打开同步,要么在宿主侧统一施加策略。vcluster-generic-crd-sync-plugin 插件已废弃,功能已内置到 fromHost.customResources / toHost.customResources,新部署不要再引入这个插件。vcluster connect 会切换 kube context,忘记 vcluster disconnect 就继续敲 kubectl delete 是真实事故来源。习惯用 kubectl config current-context 确认一下。--distro 决定,与宿主版本无关。kubectl — Kubernetes集群管理工具namespace — vcluster 的宿主载体,理解命名空间边界是前提k3s — vcluster 默认的控制面发行版k0s — 可选的另一种控制面发行版helm — vcluster 底层由 Helm 部署,values 即 chart valuescapsule — 命名空间级多租户方案,与 vcluster 常被比较multi-tenancy — 多租户隔离的整体取舍