1. 为什么要在 vSphere 7 上跑 Tanzu Kubernetes 集群
很多做企业级虚拟化的朋友,第一次听到“在 vSphere 上跑 Kubernetes”时,脑子里冒出来的第一个问题往往是:我直接开几台虚拟机装 kubeadm 不就行了吗,为什么还要折腾 Tanzu?这个问题我在三年前第一次接触 vSphere 7 与 Tanzu 的组合时也问过自己。后来在一个需要同时管理几十个业务集群的场景里踩了一圈坑,才真正理解这套组合的价值所在。
简单说,vSphere 7 的 Tanzu Kubernetes 集群(官方叫 TKG,Tanzu Kubernetes Grid)不是让你“多一种装 K8s 的方式”,而是把 Kubernetes 集群本身变成了 vSphere 里的一等公民资源。你可以像创建一台虚拟机那样,通过声明式的方式创建、升级、扩缩容一个完整的 K8s 集群,底层用的是 vSphere 的 ESXi 主机、vSAN 存储、NSX 网络,上层暴露给开发者的是标准的 Kubernetes API。这个定位决定了它适合谁:适合已经有 vSphere 虚拟化底座、又需要给内部团队提供标准化 K8s 环境的企业运维和平台工程师,而不是单机玩票的个人开发者。
这里有个关键概念必须先理清楚,否则后面所有操作都会晕:vSphere with Tanzu 的架构里其实有两层 Kubernetes。第一层叫 Supervisor Cluster(主管集群),它是运行在 ESXi 之上的一个特殊 K8s 集群,由 vSphere 自己管理,你平时不直接往里面部署业务;第二层才是 Tanzu Kubernetes 集群(也叫 Guest Cluster 或 TKC),它是 Supervisor Cluster 通过“Tanzu Kubernetes Grid Service”这个能力动态创建出来的、真正给你跑业务的集群。很多人第一次配置失败,就是因为把这两层搞混了,以为 Supervisor 就是自己要用的集群。
那为什么非要这么设计?核心原因是职责分离。Supervisor Cluster 负责和 vSphere 的基础设施对接——它通过 VM Operator、Storage Operator、Network Operator 这些组件,把 ESXi、vSAN、NSX 的能力翻译成 K8s 的 API 对象。而 Tanzu Kubernetes 集群只关心业务负载,它不需要知道底层存储是 vSAN 还是别的什么,只需要声明一个 StorageClass 就能拿到持久卷。这种分层让平台团队和业务团队各管各的,平台团队维护 Supervisor 和底层资源池,业务团队只管申请 TKC 和部署应用。
从实际收益看,这套方案解决的核心痛点是集群生命周期管理的标准化。传统方式下,你要升级一个 K8s 集群,得手动 drain 节点、替换二进制、调 kubelet 参数,几十个集群就是几十倍的重复劳动。而在 vSphere with Tanzu 里,升级 TKC 就是改一个版本号字段,剩下的滚动升级由系统自动完成。我实测过一个 3 节点的 TKC 从 1.21 升到 1.23,全程大约 12 分钟,期间业务 Pod 通过 PDB(PodDisruptionBudget)保证了可用性,没有人工介入。这个效率差距,在集群数量上到两位数以后会非常明显。
不过也要泼一盆冷水:这套方案对底层环境有硬性要求。vSphere 必须是 7.0 Update 1 及以上(早期 7.0 GA 版本功能不全),ESXi 主机建议至少 3 台做 HA,存储要么用 vSAN 要么用支持 CSI 的外部存储,网络最好有 NSX-T 或者至少是 Distributed Switch。如果这些条件不满足,硬上会非常痛苦。我见过有团队用单台 ESXi 加本地存储去试,结果 Supervisor 启用都过不去,白白浪费两天。所以动手之前,先对照官方兼容性矩阵把环境盘一遍,这一步省不得。
2. 启用 Supervisor Cluster 前必须搞定的环境准备
2.1 计算与存储资源的规划逻辑
在 vSphere Client 里点“启用 Supervisor Cluster”之前,资源规划是最容易被低估的一步。Supervisor Cluster 本身不是零成本的,它需要在你的集群里占用一批 ESXi 主机作为“控制平面”载体。具体来说,启用时你会创建一个“Supervisor 控制平面”的资源池,vSphere 会在选定的三台 ESXi 主机上各部署一台控制平面虚拟机,这三台机器组成一个高可用的 K8s 控制面。
为什么是三台?因为 Supervisor 的控制平面跑的是标准 K8s 的 etcd 和 API Server,etcd 需要奇数节点做仲裁,三台是最小的高可用配置。这三台控制平面 VM 每台建议至少 4 vCPU、16GB 内存,也就是说你至少要预留 12 vCPU、48GB 内存给 Supervisor 本身,这还没算后面要跑的 TKC。我见过一个团队在只有 2 台 ESXi 的集群上尝试启用,结果因为无法满足反亲和性要求(三台控制平面 VM 必须分布在不同主机上)直接失败。所以启用 Supervisor 的集群至少要有 3 台 ESXi 主机,这是硬门槛。
存储方面,Supervisor 控制平面 VM 需要放在共享存储上,因为三台 VM 可能分布在不同主机,本地存储会导致迁移和 HA 失效。如果你用 vSAN,需要提前把 vSAN 集群配好并确认健康状态;如果用外部存储(比如某类支持 CSI 的集中式存储),要确保 ESXi 主机能识别到数据存储。这里有个细节:vSAN 的存储策略会直接影响后面 TKC 的持久卷行为。默认的 vSAN 策略是“厚置备、RAID-1”,如果你希望 TKC 里的 PVC 用 RAID-5 或 RAID-6 节省空间,需要在 vSAN 里预先建好对应的存储策略,后面在 TKC 的 StorageClass 里引用。
网络规划同样关键。Supervisor Cluster 需要一个“管理网络”(用于 ESXi 和 Supervisor 通信)和一个“工作负载网络”(用于 TKC 的 Pod 和 Service)。如果只有标准 vSphere Distributed Switch(vDS),工作负载网络可以用“NSX-T 之外的方案”——也就是 vSphere 7 自带的“NSX 无关”模式,官方叫“vSphere Networking”模式,它通过 vDS 的端口组和一段可路由的 IP 段来实现。但如果要用更高级的网络策略(比如 NetworkPolicy、负载均衡器自动分配 IP),就需要 NSX-T。我的建议是:如果只是内部测试或小规模使用,vSphere Networking 模式足够;如果要上生产且需要细粒度网络控制,直接上 NSX-T,别走弯路。
2.2 内容库与镜像准备的那些坑
启用 Supervisor 之前,还有一个经常被忽略的准备工作:内容库(Content Library)。Tanzu Kubernetes 集群的节点 VM 是用 OVA 模板部署的,这些模板必须放在一个内容库里,Supervisor 才能引用。vSphere 7 自带一个“Tanzu Kubernetes Grid Service”的订阅内容库,但默认是空的,需要你手动订阅官方的镜像源。
订阅的时候有个坑:内容库的下载是走 HTTPS 的,如果你的 vCenter 所在网络不能直接访问外网,订阅会一直卡在“同步中”。这种情况下需要提前把 OVA 文件下载到本地,建一个本地内容库再导入。我踩过一次,订阅了半小时没动静,查日志才发现是 DNS 解析失败。所以动手前先确认 vCenter 的网络出口,或者干脆用离线导入的方式。
另外,内容库的存储位置也要规划。一个完整的 TKG 镜像集大概几十 GB,如果内容库放在容量紧张的存储上,同步到一半空间不足会失败。建议单独划一个数据存储给内容库,或者至少确认剩余空间是镜像大小的两倍以上(因为同步过程中会有临时文件)。
2.3 启用 Supervisor 时的参数选择
真正点“启用 Supervisor Cluster”的时候,向导会问你几个关键参数,这里逐个说清楚:
- 集群名称:随便起,但建议有含义,比如
supervisor-prod,因为后面用 kubectl 切换 context 时会看到这个名字。 - 控制平面大小:有“小/中/大”三档,对应不同的 vCPU 和内存。测试环境选“小”就行,生产建议“中”起步。我实测“小”档在跑十几个 TKC 时 API Server 响应会变慢,因为控制平面资源不够。
- 存储策略:选一个能覆盖所有 ESXi 主机的 vSAN 或 VMFS 策略。如果选错,控制平面 VM 会部署失败。
- 管理网络:选一个所有 ESXi 主机都能连通的端口组,并给 Supervisor 分配一段静态 IP(至少 5 个,三台控制平面 VM 加一个浮动 IP 加一个预留)。
- 工作负载网络:如果选 vSphere Networking 模式,需要指定一个端口组和一段 IP 段(用于 TKC 的 Pod 和 Service),这段 IP 段不能和节点网络冲突。
启用过程大概需要 15 到 30 分钟,期间 vSphere 会在后台部署一堆 Operator 和 CRD。判断成功的标志是:在 vSphere Client 的“工作负载管理”里能看到 Supervisor Cluster 状态变成“正在运行”,并且能下载到 Supervisor 的 kubeconfig。如果卡在“配置中”超过 40 分钟,大概率是某个 Operator 起不来,去 ESXi 主机上看控制平面 VM 的日志,通常是存储或网络问题。
3. 从 Supervisor 到 Tanzu Kubernetes 集群的创建链路
3.1 命名空间:TKC 的“资源租户”边界
Supervisor Cluster 跑起来之后,你拿到的 kubeconfig 是连到 Supervisor 的。这时候如果你直接kubectl get nodes,看到的是三台控制平面 VM,这不是给你跑业务的。要创建真正的 TKC,第一步是在 Supervisor 里创建一个命名空间(Namespace),这个命名空间在 vSphere with Tanzu 里被赋予了特殊含义——它相当于一个“资源租户”,每个命名空间可以配置自己的资源配额、存储策略、网络策略,然后在这个命名空间里创建 TKC。
为什么要有这一层?因为企业里通常有多个团队共用一套 vSphere,你不想让 A 团队的 TKC 把资源吃光导致 B 团队创建失败。命名空间级别的资源配额(ResourceQuota)可以限制这个租户最多能用多少 vCPU、多少内存、多少个 TKC。我一般建议给每个业务团队建一个命名空间,配额按团队规模分配,比如小团队给 20 vCPU、64GB 内存,够跑一个 3 节点的 TKC。
创建命名空间有两种方式:在 vSphere Client 的“工作负载管理”里点图形界面,或者用 kubectl 直接 apply 一个 YAML。图形界面更直观,但 kubectl 方式更适合自动化。这里给一个 kubectl 创建命名空间的示例:
apiVersion: v1 kind: Namespace metadata: name: team-alpha labels: pod-security.kubernetes.io/enforce: baseline创建完之后,还需要给这个命名空间绑定一个“存储策略”和“虚拟机类”(VM Class)。存储策略决定了 TKC 节点 VM 的存储行为,虚拟机类决定了节点 VM 的规格(比如 2 vCPU/8GB 还是 4 vCPU/16GB)。这两个都是 vSphere 层面的概念,通过 Supervisor 的 CRD 暴露出来。你可以用kubectl get storagepolicies和kubectl get virtualmachineclasses查看可用的选项。
3.2 用 TanzuKubernetesCluster 资源声明一个集群
真正创建 TKC 的核心,是提交一个TanzuKubernetesCluster自定义资源。这个 YAML 定义了集群的拓扑:控制平面几个节点、工作节点几个、用什么版本、什么存储类、什么虚拟机类。下面是一个典型的三控制平面加三工作节点的配置:
apiVersion: run.tanzu.vmware.com/v1alpha3 kind: TanzuKubernetesCluster metadata: name: tkc-prod-01 namespace: team-alpha spec: topology: controlPlane: replicas: 3 vmClass: guaranteed-medium storageClass: vsan-default tkr: reference: name: v1.23.8---vmware.1-tkg.1 nodePools: - name: worker-pool-01 replicas: 3 vmClass: guaranteed-medium storageClass: vsan-default tkr: reference: name: v1.23.8---vmware.1-tkg.1 distribution: fullVersion: v1.23.8+vmware.1-tkg.1 settings: network: cni: name: antrea services: cidrBlocks: ["10.96.0.0/12"] pods: cidrBlocks: ["192.168.128.0/17"]这里有几个参数值得展开说。tkr.reference.name是 Tanzu Kubernetes Release 的版本标识,它对应内容库里同步下来的某个 OVA 版本。你不能随便写一个 K8s 版本号,必须是内容库里实际存在的 TKR。用kubectl get tkr可以列出所有可用版本。vmClass决定了节点 VM 的规格,guaranteed-medium通常对应 2 vCPU/8GB,guaranteed-large对应 4 vCPU/16GB。生产环境建议控制平面用 medium 以上,工作节点根据业务负载选。storageClass必须是在该命名空间里可用的存储策略,如果写了一个不存在的,集群会卡在创建中。
提交这个 YAML 之后,Supervisor 会开始干活:它先创建控制平面 VM,等控制平面就绪后再创建工作节点 VM,最后把 kubeconfig 存到一个 Secret 里。整个过程大概 8 到 15 分钟。查看进度的命令是kubectl get tkc -n team-alpha,状态会从creating变成running。如果卡在creating,用kubectl describe tkc tkc-prod-01 -n team-alpha看事件,通常是资源不足或存储策略不匹配。
3.3 拿到 TKC 的 kubeconfig 并验证
集群变成running之后,kubeconfig 会被放在一个 Secret 里,名字通常是tkc-prod-01-kubeconfig。取出它的命令是:
kubectl get secret tkc-prod-01-kubeconfig -n team-alpha -o jsonpath='{.data.value}' | base64 -d > tkc-prod-01.kubeconfig然后export KUBECONFIG=tkc-prod-01.kubeconfig,再kubectl get nodes,应该能看到三台控制平面和三台工作节点,全部Ready。这时候你才真正拥有了一个可以跑业务的 K8s 集群。
这里有个经验:TKC 的 kubeconfig 默认有效期是有限的(通常和 Supervisor 的证书周期一致),如果长期使用,建议在 Supervisor 层面配置证书轮换,或者定期重新导出。我遇到过用了一个月的 kubeconfig 突然失效,排查半天才发现是证书过期。另外,TKC 的 API Server 是通过 Supervisor 的浮动 IP 暴露的,如果 Supervisor 的浮动 IP 变了(比如重启后重新分配),kubeconfig 里的 server 地址也要跟着改。
4. 在 TKC 上部署业务时的存储与网络实操
4.1 持久化存储:StorageClass 与 PVC 的绑定逻辑
TKC 跑起来之后,第一个要解决的问题通常是持久化存储。默认情况下,TKC 里会有一个名为default的 StorageClass,它背后对应的是你在创建集群时指定的存储策略。但如果你直接用这个默认的,可能会发现 PVC 一直处于Pending。原因通常是存储策略的“置备方式”和 TKC 的 CSI 驱动不匹配。
vSphere with Tanzu 用的是 vSphere CSI 驱动,它要求存储策略必须是“基于标签”或“基于 vSAN 规则”的。如果你在 vSphere 里建了一个基于“VMFS 数据存储”的策略,CSI 驱动可能无法识别。我建议的做法是:在 vSAN 里建一个专门的存储策略,比如叫tkc-gold,规则设为“RAID-1、厚置备”,然后在 TKC 里创建一个引用这个策略的 StorageClass。创建 StorageClass 的 YAML 大概长这样:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: tkc-gold provisioner: csi.vsphere.vmware.com parameters: storagePolicyName: tkc-gold datastoreURL: "ds:///vmfs/volumes/vsan:xxx" reclaimPolicy: Delete allowVolumeExpansion: true注意storagePolicyName必须和 vSphere 里的策略名完全一致,datastoreURL可以用kubectl get datastore在 Supervisor 里查到。创建完 StorageClass 后,再建一个 PVC 测试:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteOnce storageClassName: tkc-gold resources: requests: storage: 10Gi如果 PVC 能在几十秒内变成Bound,说明存储链路通了。如果一直Pending,用kubectl describe pvc test-pvc看事件,常见原因是存储策略不存在、vSAN 空间不足、或者 CSI 驱动 Pod 没起来(用kubectl get pods -n vmware-system-csi检查)。
4.2 网络策略与负载均衡器的实际表现
TKC 默认用的 CNI 是 Antrea,它支持 NetworkPolicy,也支持 LoadBalancer 类型的 Service。但在 vSphere Networking 模式下,LoadBalancer 的 IP 分配需要依赖 Supervisor 层面的“负载均衡器”配置。如果你在创建 TKC 时没有配置负载均衡器,那么type: LoadBalancer的 Service 会一直处于Pending,因为没有组件给它分配外部 IP。
解决方式有两种:一是在 Supervisor 层面启用“NSX-T 负载均衡器”或“vSphere 原生负载均衡器”,二是在 TKC 里用 NodePort 加外部反向代理。我实测下来,如果只是内部测试,NodePort 加一个 Nginx Ingress 就够了;如果要生产级别的 LoadBalancer,还是得配 NSX-T 的负载均衡器,它能自动分配 IP 并做健康检查。
NetworkPolicy 方面,Antrea 的表现很稳。我试过在一个 TKC 里用 NetworkPolicy 限制某个命名空间的 Pod 只能访问特定端口,规则生效后,跨命名空间的流量被正确阻断。但要注意:NetworkPolicy 是命名空间级别的,默认拒绝所有入站流量,你需要显式允许 DNS 和必要的出站。很多新手配完策略后发现 Pod 解析不了域名,就是因为忘了放行 DNS 的 53 端口。
4.3 节点池扩缩容与滚动升级的实测数据
TKC 的一个实用能力是节点池(NodePool)的动态扩缩容。你可以通过修改TanzuKubernetesCluster资源里的nodePools[].replicas字段来增减工作节点。比如把replicas从 3 改成 5,Supervisor 会在几分钟内创建两台新 VM 并加入集群。我实测从提交修改到新节点Ready,大约 4 到 6 分钟,取决于存储和网络的响应速度。
滚动升级则是改tkr.reference.name到新版本。升级过程中,Supervisor 会先创建新版本的节点,然后逐个 drain 旧节点,把 Pod 迁移过去,最后删除旧节点。关键是要提前配置好 PDB,否则如果某个应用的副本数只有 1,drain 的时候会卡住。我建议在升级前用kubectl get pdb -A检查一遍,确保所有关键应用都有 PDB 且ALLOWED DISRUPTIONS大于 0。
还有一个坑:升级 TKC 的 K8s 版本时,不能跨太多小版本。比如从 1.21 直接升到 1.25 可能会失败,因为 TKR 的升级路径是有限制的。官方建议一次升一个小版本,比如 1.21 到 1.22 再到 1.23。我试过跨两个版本升,结果卡在upgrading状态,最后只能删了重建。所以升级前先查一下 TKR 的兼容性矩阵,规划好路径。
5. 踩过的坑与日常运维的几条硬经验
5.1 Supervisor 证书过期导致 TKC 失联
这是我在生产环境遇到的第一个大坑。Supervisor Cluster 的 API Server 证书默认有效期是一年,到期后所有 TKC 的 kubeconfig 都会失效,表现为kubectl报x509: certificate has expired。更麻烦的是,这时候你连 Supervisor 都连不上,没法直接轮换证书。
解决办法是提前在 vSphere Client 里配置证书自动轮换,或者至少设置一个到期提醒。如果已经过期了,需要通过 ESXi 主机的 SSH 登录到控制平面 VM,手动执行证书轮换脚本。这个过程比较繁琐,而且有风险,所以最好的策略是预防。我现在的做法是在日历里设一个 11 个月后的提醒,提前一个月处理。
5.2 资源配额算错导致 TKC 创建卡死
前面提到命名空间可以设资源配额,但很多人不知道配额的计算方式是按“预留”算的,不是按“实际使用”算的。比如你给命名空间设了 20 vCPU 的配额,创建一个 3 控制平面加 3 工作节点的 TKC,每个节点 2 vCPU,那就是 12 vCPU 的预留,看起来没超。但如果你再创建一个同样规模的 TKC,就需要 24 vCPU,超过配额,第二个 TKC 会卡在creating状态,事件里会提示exceeded quota。
更隐蔽的是,删除 TKC 后配额不会立即释放,因为 VM 的删除是异步的。我遇到过删了旧集群后马上建新集群,结果配额不够,等了十分钟才恢复。所以做集群轮换时,要留出足够的缓冲时间,或者临时调大配额。
5.3 存储策略不匹配引发的 PVC 批量 Pending
有一次客户反馈说,他们所有 TKC 里的 PVC 都 Pending 了,之前一直好好的。排查发现,是 vSAN 的存储策略被运维改了——原本的tkc-gold策略被删了,新建了一个同名但规则不同的策略。CSI 驱动在置备 PVC 时会去查存储策略,发现规则不匹配(比如原本要求 RAID-1,新策略是 RAID-5),就拒绝置备。
这个问题的教训是:vSphere 里的存储策略一旦被 TKC 引用,就不要随意修改或删除。如果必须改,要先在所有 TKC 里把引用该策略的 StorageClass 和 PVC 处理掉,改完再重建。日常运维中,建议给 TKC 用的存储策略加一个明确的命名前缀,比如tkc-,和普通虚拟机的策略区分开,避免误操作。
5.4 日常巡检该看哪些指标
跑起来之后,日常巡检不需要太复杂,我一般看这几个地方:
| 检查项 | 命令或位置 | 正常表现 | 异常处理 |
|---|---|---|---|
| Supervisor 状态 | vSphere Client 工作负载管理 | 正在运行 | 重启 Supervisor 或查 Operator 日志 |
| TKC 集群状态 | kubectl get tkc -A | running | describe 看事件 |
| 节点就绪 | kubectl get nodes | 全部 Ready | 查 kubelet 和网络 |
| CSI 驱动 | kubectl get pods -n vmware-system-csi | 全部 Running | 重启驱动 Pod |
| 存储配额 | vSphere Client 数据存储 | 剩余空间 > 20% | 扩容或清理 |
| 证书有效期 | Supervisor 证书管理 | 剩余 > 30 天 | 轮换证书 |
这套巡检我一般一周做一次,每次十分钟左右,能提前发现大部分问题。特别是存储空间和证书,这两个是“慢性病”,不查的话等到爆发就晚了。
5.5 什么时候该考虑多 Supervisor 或多 vSphere 集群
最后说一个架构层面的经验。单个 Supervisor Cluster 能管理的 TKC 数量是有限的,官方没有给硬性上限,但实测下来,当 TKC 数量超过 50 个、或者总节点数超过 300 个时,Supervisor 的 API Server 响应会明显变慢。这时候可以考虑部署多个 Supervisor Cluster,比如按业务线拆分,每个 Supervisor 管一批 TKC。
另外,如果 vSphere 集群本身规模很大(比如超过 32 台 ESXi 主机),也建议拆成多个 vSphere 集群,每个集群跑一个 Supervisor。这样故障域更小,升级维护也更灵活。当然,拆分的代价是管理复杂度上升,需要一套统一的命名和标签规范来跟踪。我一般建议在 TKC 的命名里带上业务线和环境标识,比如tkc-payment-prod-01,这样在多个 Supervisor 之间切换时不容易搞混。
这套东西说到底,核心价值是把 K8s 集群的运维从“手工活”变成“声明式操作”。但声明式不代表零维护,底层存储、网络、证书这些还是得有人盯着。我的体会是:把 Supervisor 当成一个需要精心维护的基础设施组件,而不是一个装完就不管的黑盒,这样跑起来才稳。