Skip to content

필사 모드: 用 vCluster 实现 Kubernetes 多租户:虚拟集群隔离与运维指南

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
vCluster Multi-Tenancy

前言

运维 Kubernetes 时必然会遇到的一个课题,就是 多租户(Multi-Tenancy) 问题。如何在一个物理集群之上安全地隔离多个团队、项目或客户的工作负载,同时又优化基础设施成本,这一诉求随着组织规模扩大会变得越来越迫切。传统做法是组合命名空间隔离、RBAC 策略、NetworkPolicy 等手段来实现多租户,但仍然存在本质性局限:CRD 安装权限冲突、共享 API Server 带来的 noisy neighbor 问题、无法按租户独立升级集群等。

vCluster 是 Loft Labs(现 vCluster Labs)开发的开源项目,它通过在宿主集群的命名空间内运行 虚拟 Kubernetes 集群 的方式解决了上述问题。每个虚拟集群都拥有独立的 API Server、Controller Manager 和数据存储(etcd 或 SQLite),因此既能把完整的集群管理权限交给租户,实际的计算资源又仍然共享宿主集群。作为 CNCF 项目,它在 2025 年的 KubeCon EU 上发布了 vNode,新增了节点级别的虚拟化隔离层;同年还推出了 Standalone vCluster,使虚拟集群即使没有宿主集群也能独立运行。

本文从 vCluster 的架构原理讲起,综合介绍安装、配置、Syncer 机制、RBAC 策略、资源配额、网络隔离、监控集成,以及真实生产环境中可能遇到的失败案例与恢复流程。

vCluster 架构

vCluster 的核心思路是 把宿主集群的一个命名空间当作虚拟集群的运行环境。在虚拟集群内部创建的工作负载会通过 Syncer 组件,在宿主集群的对应命名空间中被调度为真实的 Pod。

组成要素

vCluster 由以下主要组件构成。

  1. Control Plane:运行虚拟集群专用的 API Server 与 Controller Manager。默认使用 k3s,也可以选择 k0s 或 vanilla k8s(含 EKS distro)。
  2. Data Store:使用 etcd、SQLite 或外部数据库(PostgreSQL、MySQL)作为数据存储。基于 k3s 部署时默认值是内置 SQLite。
  3. Syncer:负责虚拟集群与宿主集群之间资源同步的核心组件。
  4. CoreDNS:负责虚拟集群内部的 DNS 解析,并与宿主集群的 DNS 联动以支持服务发现。

隔离级别层次

vCluster 提供三种隔离级别。

  • Shared(共享):默认模式。虚拟集群运行在宿主集群的命名空间内,并共享宿主集群的节点。
  • Private(专用):为虚拟集群分配专用节点,从物理上隔离计算资源。
  • Standalone(独立):不依赖宿主集群、独立运行的虚拟集群。这是 2025 年引入的能力,可保证完整的集群自治。

命名空间隔离 vs vCluster 对比表

下面从多个角度对比传统的命名空间多租户方案与基于 vCluster 的虚拟集群方案。

项目命名空间隔离vCluster 虚拟集群
API Server共享(所有租户同一个 API Server)独立(每个租户专用 API Server)
CRD 安装影响整个集群,存在冲突风险可在虚拟集群内独立安装
RBAC 复杂度租户增多时策略爆炸式增长每租户独立 RBAC,管理更简单
资源隔离基于 ResourceQuota/LimitRange 的软隔离虚拟集群 + 宿主配额的双重隔离
网络隔离必须配置 NetworkPolicy默认命名空间隔离 + 可追加 NetworkPolicy
集群升级影响整个集群,需同时进行可按虚拟集群独立升级
Admission Webhook全局生效,租户之间互相影响可按虚拟集群独立配置
成本效率高(开销最小)中(存在控制平面开销)
实现难度中(需要理解 Syncer 与网络)
租户自治度低(依赖集群管理员)高(可拥有虚拟 cluster-admin)

安装与配置

使用 CLI 快速安装

使用 vCluster CLI 可以最快速地创建虚拟集群。

# 安装 vCluster CLI
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin/

# 创建虚拟集群(默认基于 k3s)
vcluster create my-vcluster --namespace team-alpha

# 连接虚拟集群(自动配置 kubeconfig)
vcluster connect my-vcluster --namespace team-alpha

# 确认连接
kubectl get namespaces
kubectl get nodes

# 断开虚拟集群连接
vcluster disconnect

# 删除虚拟集群
vcluster delete my-vcluster --namespace team-alpha

使用 Helm 进行生产部署

在生产环境中,推荐使用 Helm chart 来应用精细化配置。下面是生产级别的 vcluster.yaml 配置示例。

# vcluster.yaml - 生产配置示例
controlPlane:
  # 使用 k8s 而非 k3s(生产推荐)
  distro:
    k8s:
      enabled: true
      apiServer:
        extraArgs:
          - '--audit-log-path=/var/log/kubernetes/audit.log'
          - '--audit-log-maxage=30'
          - '--audit-log-maxbackup=10'
          - '--audit-log-maxsize=100'
      controllerManager:
        extraArgs:
          - '--terminated-pod-gc-threshold=50'

  # 控制平面资源限制
  statefulSet:
    resources:
      limits:
        cpu: '2'
        memory: 4Gi
      requests:
        cpu: '500m'
        memory: 1Gi
    persistence:
      size: 20Gi

  # 使用外部 etcd(高可用)
  backingStore:
    etcd:
      deploy:
        enabled: true
        statefulSet:
          resources:
            limits:
              cpu: '1'
              memory: 2Gi
            requests:
              cpu: '200m'
              memory: 512Mi

# 资源同步配置
sync:
  toHost:
    pods:
      enabled: true
    services:
      enabled: true
    configmaps:
      enabled: true
    secrets:
      enabled: true
    endpoints:
      enabled: true
    persistentvolumeclaims:
      enabled: true
    ingresses:
      enabled: true
    storageClasses:
      enabled: false
  fromHost:
    nodes:
      enabled: true
      selector:
        labels:
          team: alpha
    storageClasses:
      enabled: true
    ingressClasses:
      enabled: true

# 网络配置
networking:
  replicateServices:
    fromHost:
      - from: monitoring/prometheus-server
        to: monitoring/prometheus-server
  resolveDNS:
    - hostname: '*.team-alpha.svc.cluster.local'
      target:
        hostNamespace: team-alpha

# 安全策略
policies:
  resourceQuota:
    enabled: true
    quota:
      requests.cpu: '8'
      requests.memory: '16Gi'
      limits.cpu: '16'
      limits.memory: '32Gi'
      pods: '50'
      services: '20'
      persistentvolumeclaims: '10'
  limitRange:
    enabled: true
    default:
      cpu: '500m'
      memory: '512Mi'
    defaultRequest:
      cpu: '100m'
      memory: '128Mi'

使用 Helm chart 进行部署的命令如下。

# 添加 Helm 仓库
helm repo add loft https://charts.loft.sh
helm repo update

# 创建命名空间
kubectl create namespace team-alpha

# 部署 vCluster
helm upgrade --install my-vcluster loft/vcluster \
  --namespace team-alpha \
  --values vcluster.yaml \
  --version 0.24.1

# 确认部署状态
kubectl get pods -n team-alpha
kubectl get statefulset -n team-alpha

# 连接 vCluster
vcluster connect my-vcluster -n team-alpha

Syncer 工作原理

Syncer 是 vCluster 的核心引擎,负责虚拟集群与宿主集群之间的资源同步。准确理解这套机制是 vCluster 运维的关键。

同步方向与资源类型

Syncer 的同步分为两个方向。

虚拟 -> 宿主(toHost):在虚拟集群中创建的资源会真实地创建到宿主集群的命名空间中。Pod、Service、ConfigMap、Secret、PVC 等按这个方向同步。在虚拟集群中创建 Deployment 时,Deployment 本身只存在于虚拟集群的 etcd 中,但最终产生的 Pod 会作为真实 Pod 调度到宿主集群的命名空间。

宿主 -> 虚拟(fromHost):把宿主集群的资源同步进来,使其可以在虚拟集群内部使用。StorageClass、IngressClass、Node 信息、PriorityClass 等按这个方向同步。

资源名称转换(Name Rewriting)

Syncer 在把虚拟集群的资源同步到宿主集群时,会转换名称以避免命名冲突。默认转换规则是 {vcluster-name}-x-{resource-name}-x-{vcluster-namespace} 形式。例如在虚拟集群 my-vclusterdefault 命名空间中创建 nginx Pod,在宿主集群中就会以 my-vcluster-x-nginx-x-team-alpha 的名称创建。

标签与注解传播

Syncer 会在宿主集群的资源上附加额外标签,以维持与虚拟集群的关联关系。vcluster.loft.sh/managed-byvcluster.loft.sh/namespace 等标签会被自动添加,用于垃圾回收与资源追踪。

高级同步:Generic Sync

当需要同步默认支持范围之外的自定义资源(CRD)时,可以使用 Generic Sync 功能。借此可以把 Cert-Manager 的 Certificate、Istio 的 VirtualService 等自定义资源也从虚拟集群同步到宿主集群。

RBAC 与资源配额配置

虚拟集群用户 RBAC

在虚拟集群内部,可以给租户授予 cluster-admin 权限。由于该权限只在虚拟集群范围内有效,因此不会影响宿主集群的安全性。

# vcluster-tenant-rbac.yaml
# 在虚拟集群内部给租户授予 admin 权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tenant-admin-binding
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
# 在宿主集群中限制对 vCluster 命名空间的访问
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: vcluster-namespace-viewer
  namespace: team-alpha
rules:
  - apiGroups: ['']
    resources: ['pods', 'services', 'configmaps']
    verbs: ['get', 'list', 'watch']
  - apiGroups: ['']
    resources: ['pods/log']
    verbs: ['get']
  - apiGroups: ['apps']
    resources: ['statefulsets']
    verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: vcluster-namespace-viewer-binding
  namespace: team-alpha
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: vcluster-namespace-viewer
  apiGroup: rbac.authorization.k8s.io

宿主集群资源配额

为了防止虚拟集群过度消耗宿主集群的资源,需要给虚拟集群所在的命名空间应用 ResourceQuota。

# host-resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: vcluster-team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: '8'
    requests.memory: '16Gi'
    limits.cpu: '16'
    limits.memory: '32Gi'
    pods: '50'
    services: '20'
    services.loadbalancers: '2'
    services.nodeports: '5'
    persistentvolumeclaims: '10'
    requests.storage: '100Gi'
    count/deployments.apps: '30'
    count/statefulsets.apps: '10'
    count/jobs.batch: '20'
    count/cronjobs.batch: '10'
---
apiVersion: v1
kind: LimitRange
metadata:
  name: vcluster-team-alpha-limits
  namespace: team-alpha
spec:
  limits:
    - type: Container
      default:
        cpu: '500m'
        memory: '512Mi'
      defaultRequest:
        cpu: '100m'
        memory: '128Mi'
      max:
        cpu: '4'
        memory: '8Gi'
      min:
        cpu: '50m'
        memory: '64Mi'
    - type: Pod
      max:
        cpu: '8'
        memory: '16Gi'
    - type: PersistentVolumeClaim
      max:
        storage: '50Gi'
      min:
        storage: '1Gi'

网络隔离(NetworkPolicy)

在 vCluster 环境中,网络隔离要在两个层面实现。首先在宿主集群层面控制各虚拟集群命名空间之间的通信,另外还可以在虚拟集群内部对工作负载之间应用更细粒度的策略。

宿主集群层面的 NetworkPolicy

# host-networkpolicy.yaml
# 阻断虚拟集群命名空间之间的通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-vcluster-namespace
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # 允许同一命名空间内的通信
    - from:
        - podSelector: {}
    # 允许来自 Ingress 控制器的流量
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
    # 允许监控系统采集指标
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: monitoring
          podSelector:
            matchLabels:
              app: prometheus
  egress:
    # 允许 DNS 查询
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    # 允许同一命名空间内的通信
    - to:
        - podSelector: {}
    # 允许访问外部互联网(按需)
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16

这条 NetworkPolicy 隔离了虚拟集群所在的宿主命名空间,阻断与其他租户命名空间的直接通信,同时放行与 Ingress 控制器、监控系统、DNS 等必要基础设施服务的通信。

虚拟集群内部的 NetworkPolicy

在虚拟集群内部同样可以对微服务之间应用网络策略。在虚拟集群内部定义的 NetworkPolicy 会通过 Syncer 被恰当地转换后应用到宿主集群。

监控集成

Prometheus 指标采集

要对 vCluster 的控制平面以及虚拟集群内部工作负载进行监控,需要配置宿主集群的 Prometheus,使其能够抓取虚拟集群命名空间中的 Pod。

可以在宿主集群的 Prometheus 中添加 ServiceMonitor,采集虚拟集群控制平面的指标。把 vCluster 的 API Server 指标、etcd 指标、Syncer 的同步状态指标都纳入进来,就能综合监控控制平面的健康状况。其中 Syncer 的同步延迟与错误率尤其是判断虚拟集群稳定性的核心指标。

虚拟集群内部工作负载的指标,既可以由宿主集群的 Prometheus 直接抓取对应命名空间的 Pod,也可以在虚拟集群内部单独安装 Prometheus 来采集。在多租户环境中,最好按租户配置各自的 Grafana 仪表盘,并施加访问控制,使每个团队只能查看自己工作负载的状态。

告警配置建议

在生产环境中,建议针对以下项目配置告警。

  • vCluster 控制平面 Pod 的重启次数超过阈值时
  • Syncer 的同步延迟超过 30 秒时
  • 虚拟集群命名空间的资源配额使用率超过 80% 时
  • etcd 数据存储的磁盘使用率超过 70% 时
  • 虚拟集群 API Server 的响应时间异常增长时

失败案例与恢复流程

案例 1:Syncer 同步失败导致 Pod 不一致

症状:在虚拟集群中删除了 Deployment,宿主集群中却残留了孤儿(orphan)Pod。虚拟集群的 kubectl get pods 与宿主集群的实际 Pod 列表不一致。

原因:由于 Syncer Pod 发生 OOM Kill 或出现网络分区,删除事件没有被传播出去时会发生这种情况。

恢复流程

# 1. 在宿主集群中识别孤儿 Pod
kubectl get pods -n team-alpha -l vcluster.loft.sh/managed-by=my-vcluster \
  --field-selector=status.phase=Running

# 2. 确认虚拟集群中该 Pod 是否存在
vcluster connect my-vcluster -n team-alpha
kubectl get pods --all-namespaces

# 3. 手动删除虚拟集群中不存在的孤儿 Pod
vcluster disconnect
kubectl delete pod <orphan-pod-name> -n team-alpha --grace-period=30

# 4. 重启 Syncer Pod 以恢复同步状态
kubectl rollout restart statefulset my-vcluster -n team-alpha

# 5. 确认同步状态(查看日志)
kubectl logs statefulset/my-vcluster -n team-alpha -c syncer --tail=100

预防措施:为 Syncer 设置充足的资源请求与限制,并配置 CronJob 定期检查虚拟集群与宿主集群之间的资源是否一致。

案例 2:虚拟集群 etcd 数据损坏

症状:虚拟集群 API Server 无法启动,etcd 容器日志中出现 panic: freepages: failed to get all reachable pagesdatabase file is not valid 错误。

原因:PersistentVolume 的磁盘 I/O 错误、Pod 异常终止,或存储后端故障导致 etcd 数据文件损坏。

恢复流程

  1. 把虚拟集群的 StatefulSet 缩容到 replicas: 0
  2. 如果有备份,用备份数据替换 PVC 中的数据。
  3. 如果没有备份,删除 PVC 并替换为新的 PVC,然后重建虚拟集群。这种情况下虚拟集群内部的所有元数据都会丢失,但实际工作负载 Pod 仍会在宿主集群中继续运行。
  4. 把 StatefulSet 重新扩容到 replicas: 1,并确认它能与宿主集群的既有资源重新完成同步。

预防措施:为 etcd 数据配置定期快照备份,生产环境中使用高可用 etcd 集群配置。

案例 3:资源配额超限导致工作负载部署失败

症状:虚拟集群内部创建 Pod 失败,但并没有出现 forbidden: exceeded quota 错误,而是 Pod 停留在 Pending 状态。

原因:宿主集群的 ResourceQuota 已经超限,但错误信息没有正确传播到虚拟集群的事件中,导致租户难以定位原因。

恢复流程

  1. 在宿主集群中确认该命名空间的 ResourceQuota 使用量:kubectl describe resourcequota -n team-alpha
  2. 清理不必要的资源,或者提高配额。
  3. 在 vCluster 配置中启用事件同步,让租户也能看到宿主集群的事件。

预防措施:配额使用率超过 80% 时触发告警,并在虚拟集群内部另行配置 ResourceQuota 以提前设限。

案例 4:虚拟集群之间的网络隔离失效

症状:不同虚拟集群的工作负载在宿主集群中共享同一网络,可以直接互相通信。

原因:宿主集群没有配置 NetworkPolicy,或者 CNI 插件不支持 NetworkPolicy(例如 Flannel 默认配置)。

恢复流程

  1. 确认 CNI 插件是否支持 NetworkPolicy。Calico、Cilium、WeaveNet 等支持 NetworkPolicy,而 Flannel 默认配置并不支持。
  2. 把上文网络隔离一节给出的 NetworkPolicy 应用到各虚拟集群的宿主命名空间。
  3. 创建测试 Pod 验证隔离是否正确生效,确认发往其他命名空间的通信被阻断。

案例 5:虚拟集群升级失败

症状:通过 Helm 升级 vCluster 版本后,虚拟集群的 API Server 无法启动,或与既有工作负载出现兼容性问题。

原因:大版本之间的 API 变更或 Syncer 协议变更导致不兼容。

恢复流程

  1. 升级前务必执行 etcd 快照备份。
  2. 失败时用 helm rollback my-vcluster <上一个修订号> -n team-alpha 命令回滚到旧版本。
  3. 如果回滚后问题仍然存在,则从备份恢复 etcd 数据。

预防措施:先在预发布环境测试升级,并务必确认官方升级指南中的 Breaking Changes。生产环境中应逐级渐进升级。

运维注意事项检查清单

下面整理了在生产环境运维 vCluster 时必须确认的项目。

部署前检查项

  • 确认 CNI 插件是否支持 NetworkPolicy(推荐 Calico、Cilium)
  • 确认宿主集群的 ResourceQuota 已应用到虚拟集群命名空间
  • 确认 vCluster 控制平面的资源请求与限制配置合理
  • 确认 PersistentVolume 的存储类与回收策略正确
  • 确认虚拟集群的 kubeconfig 分发流程安全(推荐接入 OIDC)

运维期监控项

  • 监控 Syncer 的同步延迟与错误率
  • 监控虚拟集群控制平面的 CPU/内存使用量
  • 监控 etcd 数据存储的磁盘使用量与压缩状态
  • 监控虚拟集群 API Server 的请求延迟与错误率
  • 监控宿主集群命名空间的资源配额使用量

备份与灾难恢复

  • 确认已配置 etcd 快照的定期备份计划(至少每日一次)
  • 确认每季度演练一次备份恢复流程
  • 确认虚拟集群的重建流程已实现自动化(IaC)
  • 确认宿主集群故障时虚拟集群的恢复流程已形成文档

安全检查项

  • 确认虚拟集群用户的认证/授权已与中央 IdP(OIDC、LDAP)集成
  • 确认宿主集群的 Node 访问权限没有暴露给虚拟集群租户
  • 确认已应用 Pod Security Standards(PSS)以阻止运行特权容器
  • 确认定期测试虚拟集群之间的网络隔离是否正常工作

升级流程

  • 升级 vCluster 版本前执行 etcd 快照备份
  • 在预发布环境完成升级测试后再应用到生产
  • 升级后确认 Syncer 同步状态与工作负载运行正常
  • 事先准备好回滚流程与命令

结语

vCluster 用虚拟集群这一抽象层,务实地化解了 Kubernetes 多租户的根本性局限。仅靠命名空间隔离难以满足的 CRD 独立性、API Server 隔离、按租户的集群管理自治度等诉求,无需额外增加物理集群即可达成。

不过,如果没有充分理解 Syncer 的工作原理与资源名称转换机制,运维时很可能遇到意料之外的问题,因此建议先在预发布环境充分验证后再引入生产。尤其是网络隔离与资源配额配置,务必在初始搭建阶段就一并落实。

参考资料

현재 단락 (1/372)

运维 Kubernetes 时必然会遇到的一个课题,就是 **多租户(Multi-Tenancy)** 问题。如何在一个物理集群之上安全地隔离多个团队、项目或客户的工作负载,同时又优化基础设施成本,这...

작성 글자: 0원문 글자: 11,682작성 단락: 0/372