第 23 章 多集群与联邦:当一个集群不够时
墨:老哥,前面 22 章我们都在”一个集群”里打转。这章抬头看上一层:当一个集群不够用,怎么管一群集群? 先问:什么情况下你会需要第二个集群?你先列三条,再往下看——我打赌你漏了”合规”那条。
23.1 为什么一个集群不够:五个推力
墨:单集群能跑无限 Pod 吗? 不能,有硬上限。K8s 官方支持的规模上限约 5000 节点 / 15 万 Pod / 30 万容器。超出,控制面(尤其 etcd 写吞吐,第 5.11/16.3)就扛不住。所以规模是第一推力。但还有更常被忽视的:
23.1.1 故障域隔离(Fault Isolation)
单集群控制面挂(etcd 全挂、API Server 雪崩),整个集群所有服务一起瞎(第 5.2/16 说业务还在跑但控制面僵死)。把业务分多个集群,一个集群控制面挂,只影响那部分。关键业务(支付)放独立集群,和”边缘业务”隔离,避免互拖。
23.1.2 合规与数据驻留(你大概率漏的)
墨:如果监管要求”欧盟用户数据不能出欧盟”,你怎么搞? 一个全球集群做不到——数据会跨区。必须按地域分集群:欧盟用户→法兰克福集群、中国用户→北京集群,数据物理留在属地。这是法律强制的多集群,不是技术选择。合规是很多大厂多集群的头号原因,比规模更硬。
23.1.3 混合云 / 多云(避免厂商锁定)
不想被一家云绑死(第 16.8 的 lock-in 担忧),或某云某区故障要能切到另一云。多集群分布在 AWS + 阿里云 + 自有 IDC,业务可跨云流动。
23.1.4 就近延迟
用户在亚洲、欧洲、美洲,单集群在一个区,跨洲延迟高。多区域集群让用户就近接入(第 9 章的拓扑感知在”跨集群”层重演)。
23.1.5 团队/环境隔离
不同团队/不同环境(prod 绝不和 dev 同集群,爆炸半径隔离)。虽可用 namespace 隔离,但”硬隔离”(不同集群不同控制面)更安全。
墨:你看这五条,是不是每条都对应前面某章的”麻烦”在”集群”层的放大? 对——故障域(第16)、合规(第13)、厂商锁定(第16.8)、延迟(第9拓扑)、隔离(第13)。多集群是把单集群的问题,“升一层”重新面对。
23.2 多集群的核心难点:每集群一套独立控制面
墨:多个集群,最直观的管理难题是什么? 每个集群有自己的 API Server、自己的 etcd、自己的 RBAC、自己的节点。它们是互相独立的控制面——你 kubectl 一次只能对一个集群(靠 kubeconfig 切 context)。于是:
- 部署一个应用到 5 个集群,要 apply 5 次(或用脚本循环);
- 集群配置(RBAC/NetworkPolicy/配额)要在 5 个集群各维护一份,易不一致;
- 某集群挂了,你靠”另一套 kubeconfig”去救,救的过程分散;
- 跨集群的服务发现/网络/存储,K8s 原生不管(Service 只在一个集群内,第 9 章)。
墨:这和”单集群里多个 Pod 没人管”的麻烦,是不是一模一样? 神似!单集群里”多个容器散在机器上”→ 用编排(K8s)管;多集群里”多个集群散在云上”→ 要用”多集群编排(联邦)“管。问题同构,层级上升——这就是计算机”递归抽象”的妙处:K8s 管节点,联邦管集群,将来可能”管多区域”。每一层都是”下一层的麻烦 + 一层抽象”。
23.3 Cluster API:把”造集群”也声明式了
墨:你说”部署到 5 集群要 apply 5 次”。如果有种办法,写一份 YAML 说”我要 5 个集群,规格这样”,然后自动把 5 个集群建出来——这可能吗? 这就是 Cluster API(CAPI)。
Cluster API 的核心思想极漂亮:把”集群”本身当成 K8s 资源(CRD)来管理。你定义一个 Cluster 对象(声明”我要个 3 节点、AWS 上的集群”),配 Machine/MachineDeployment(声明节点规格),CAPI 的控制器就去云上真正创建这些节点、装好 K8s、把控制面拉起来(第 8.9 的自举逻辑被 CAPI 用上了)。
墨:这和第 3 章、第 14 章是不是一个模子? 完全一个模子!
- 你声明”期望(Cluster 对象)”;
- CAPI 控制器调和,去云 API 创建真实资源;
- 集群状态回报到 Cluster 对象的 status。
把”造集群”变成了声明式 + 控制循环——和 K8s 管 Pod 一模一样,只是”被管的东西”从 Pod 变成了”集群”。这又一次证明第 3 章的范式有多强:只要你能把”某东西”建模成”期望状态对象 + 调和控制器”,K8s 的范式就能管它。CAPI 把 K8s 的范式,用到了”K8s 自己”身上——自举的极致。
演化看点: 早期建集群靠 kubeadm 手敲或云控制台点(命令式、易漂)。CAPI 用”声明式管集群”统一了”集群生命周期”,且集群定义也能进 Git(第 22 章 GitOps 管 Cluster 对象!)——于是”基础设施即代码”在集群层闭环:Git 里写”我要哪些集群”,CAPI 调和出集群,Argo CD 再往集群里部署应用。三层声明式(集群→应用→Pod)串成一条铁链。
23.4 联邦:把”应用”分发到多集群(Karmada 等)
CAPI 管”集群的存在”,但应用要跨集群部署/调度时,需要”联邦层”。以 Karmada 为例:
- 你有一个联邦控制面(Karmada),它连着多个成员集群;
- 你定义应用(Deployment 等)+ 一个 PropagationPolicy(“这个应用分到 cluster-A、cluster-B”);
- Karmada 控制器把应用同步到指定的成员集群,各集群自己再跑 K8s 调和出 Pod;
- 还能做跨集群调度:根据各集群资源,把应用放到”最空的集群”。
墨:Karmada 和 Argo CD 多集群模式啥区别? 两种思路:
- Argo CD(GitOps)多集群:每个集群跑一个 Argo CD 或同一个 Argo CD 管多集群的 Application,本质”Git 里的 YAML 分发到多集群”——偏”声明在 Git、按 Git 同步”(第 22 章);
- Karmada(联邦):有独立联邦控制面,应用和分发策略是联邦层的对象,偏”集中式联邦调度/治理”——适合要”跨集群统一调度、故障自动迁移”的场景。
两者可共存:Karmada 管”应用跨哪些集群”,Argo CD 管”每个集群内的 GitOps 同步”。生态里没有唯一标准,按需求选——又是”K8s 留了多种扩展口子、社区各做各的”的开放格局(第 14 章)。
23.5 多集群的”一致性”难题(别以为多集群白捡)
墨:多集群听起来美好,有坑吗? 大坑——跨集群的”一致性”比单集群难十倍:
- 网络:Service 只在单集群内(第 9 章),跨集群服务发现要额外机制(如全局负载均衡、服务网格多集群、DNS 跨集群)。Pod IP 跨集群根本不通(不同网络平面);
- 存储:PVC 是单集群的(第 10 章),跨集群迁移有状态应用极难(数据怎么跟应用走?);
- 身份/RBAC:各集群独立身份体系,跨集群的 SA/权限要 federation 或统一 OIDC(第 4.3);
- 状态一致性:一个应用跨两集群跑,它的”全局状态”在哪?缓存、数据库怎么跨集群一致?往往要应用层自己解决(如全局数据库在主集群、其他集群读副本);
- 故障切换:集群 A 挂,要把流量切到集群 B——但 B 的数据/状态跟得上吗?取决于你的数据复制策略。
墨:所以多集群不是”把单集群复制 N 份”那么简单? 对。“多集群”解决”故障域/合规/规模”,但引入了”跨集群一致性”这个新麻烦。很多团队上多集群后才发现:最难的是”有状态应用怎么跨集群”——无状态好分(副本扔不同集群),有状态(数据库)跨集群是分布式系统的老难题(主从复制、脑裂)。多集群把”单集群内已由 K8s 解决的麻烦”,在”集群间”重新暴露——又是”层级上升、麻烦重演”。
系统设计课:抽象上升一层,旧麻烦常以新形式回来。 单集群用 etcd+控制循环解决了”多 Pod 一致”,多集群要用”联邦控制面+跨集群网络/存储/身份”重新解决”多集群一致”。你设计多层系统时,预期”每升一层,下层的 guarantee 可能失效,要重新保证”。
23.6 与服务网格、GitOps 的多集群协同
这三样不是互斥,是叠加:
- GitOps 多集群(第 22):Git 里定义”哪些集群、各跑什么”,Argo CD 同步到各集群;
- 服务网格多集群(第 21):Istio 多集群模式让服务跨集群互访(mTLS + 路由跨集群),把”服务间治理”延伸到跨集群;
- 联邦(Karmada):集中调度应用到集群。
一个典型的”全球多集群”架构:GitOps(管声明) + 联邦(管分发/调度) + 服务网格(管跨集群流量治理) + CAPI(管集群存在) + 单集群 K8s(管 Pod)。五层声明式叠起来,从”集群存在”到”Pod 运行”全链路声明式。你回头看,全是第 3 章那根脊椎在不同层级的生长——这就是好范式的复利。
23.7 本章演化线小结
- 多集群五推力:规模上限/故障域/合规驻留/混合云/就近/隔离——都是单集群麻烦的升层;
- 难点:每集群独立控制面,发散管理;与”单集群多 Pod”麻烦同构、层级上升;
- Cluster API:把”集群”当 CRD + 控制器调和(声明式造集群),K8s 范式用于自身(自举);
- 联邦(Karmada):PropagationPolicy 分发应用到多集群 + 跨集群调度;
- 与 GitOps/网格协同:Git 管声明、联邦管分发、网格管跨集群流量;
- 一致性难题:跨集群网络/存储/身份/状态更难,有状态跨集群是老难题重演;
- 抽象升层,旧 guarantee 失效需重保(设计课)。
23.8 本章思考题
🔧 思考题 1
某电商”支付”和”商品推荐”两个服务,当前在同一集群。你建议拆成两个集群吗?请从 23.1 的五个推力逐条评估,给出”该拆/不该拆”的判断与条件。
【参考答案】 逐条:(1) 规模:两服务总规模若远未到 5000 节点上限,规模不是拆的理由;(2) 故障域:支付是核心、推荐是边缘,同集群则推荐若引发控制面压力(如大量 Pod 事件风暴)可能拖支付——这是拆的有力理由(隔离爆炸半径);(3) 合规:若支付涉金融数据、推荐不涉及,合规上支付可能需更强隔离/专属管控,但不一定需独立集群(namespace 隔离+PSA 可能够);(4) 混合云/锁定:无特殊诉求不拆;(5) 就近/隔离:支付低延迟要求若和推荐不同区域,可拆。判断:若仅因”故障域隔离”值得拆(支付关键、推荐易出事),其他推力不足。但拆的代价是”跨集群调用(支付调推荐或反之)网络复杂+延迟+运维双倍控制面”。更轻量替代:同集群不同 namespace + 资源配额 + 节点池隔离(支付放专属节点池 taint+toleration,第 6.3/15.4)+ 严格 RBAC——先拿”软隔离”避免硬隔离的复杂度。只有”推荐真引发过控制面级事故”或”合规强制”才上硬隔离(独立集群)。这题练你用”五个推力”做决策,而非”听说该拆就拆”——多数情况软隔离够,硬隔离是最后手段(呼应第 13/16 的权衡)。
🔧 思考题 2
Cluster API 用”声明式造集群”。对比你自己用 kubeadm 手敲/云控制台点建集群,CAPI 的”声明式”带来什么具体好处?如果 CAPI 的控制器挂了,正在创建的集群会怎样(类比 K8s 控制器挂了,第 3/16)?
【参考答案】 CAPI 声明式好处:(1) 集群定义可进 Git(第 22 GitOps 管 Cluster 对象)→ 集群生命周期也声明式、可审计、可回滚、可多环境一致;(2) 收敛自愈:cluster 期望(3节点) vs 实际(2节点,一个节点挂了) → CAPI 调和补第三个,和 K8s 补 Pod 同构(第 3 章);(3) 一致可复制:生产/测试集群用同一 Cluster 模板,规格不漂;(4) 升级集群=改 Cluster 对象版本字段,控制器滚动调和(类比 Deployment 升级)。控制器挂了:类比 K8s 控制器崩溃(第 3/16)——CAPI 控制器是选主单活(第 16.2),挂了 standby 接棒;崩溃期间”集群创建/修复”暂停,但已存在的集群继续跑(集群自己的控制面独立,不受 CAPI 控制器影响);恢复后 CAPI 重新调和(如补缺失节点)。这正说明 CAPI 把”造集群”做成了和 K8s 管 Pod 一样可靠的循环——且 CAPI 控制器自身的高可用也复用 K8s 的 leader election。你越懂第 3/16,越能预判 CAPI 行为。这题考”范式复用”:好范式到处生效。
🔧 思考题 3
你有状态应用(MySQL 主从)要跨两个集群做容灾。为什么”直接把 StatefulSet 复制到集群 B”行不通?从 23.5 的一致性难题出发,给出至少三种必须额外解决的跨集群问题,并指出这类需求通常怎么落地(而非靠 K8s 原生)。
【参考答案】 “复制 StatefulSet 到 B”行不通的原因(23.5):(1) 数据不跟应用走:StatefulSet 的 PVC 是单集群的(第 10 章),集群 A 的 MySQL 数据盘在 A 的存储,复制到 B 的 Pod 没数据,空库;(2) 跨集群网络不通:Pod IP 跨集群不可达(不同网络平面),A 的从库连不上 B 的主库做复制;(3) 身份/主从分裂:两集群各起一套主从,谁主?网络分区时两边各写=脑裂(第 7.4 主从拓扑);(4) 状态一致性:跨集群复制有延迟,切到 B 可能丢近期数据(RPO>0)。通常落地方式(非 K8s 原生):(a) 数据库层自己跨集群复制:MySQL 用 GTID 主从跨集群复制(应用层/DBA 配,非 K8s 管),K8s 只管”跑 MySQL 容器”,数据复制靠 DB 自身;(b) 存储层跨集群复制:用支持跨区复制的云存储/Portworx/ rook 等,PVC 底层数据异步复制到 B;(c) 全局流量切换:用全局 LB/DNS(如 Route53 健康检查)把流量切到存活集群;(d) 有状态应用跨集群用专用算子(如 Vitess/操作员感知跨集群)。结论:有状态跨集群容灾主要是”数据复制+全局流量”问题,K8s 原生只管”容器跑”,数据一致性得靠 DB/存储自身——K8s 不解决跨集群有状态,别指望复制 StatefulSet 就完事。这题考你认清”K8s 的能力边界在单集群有状态,跨集群有状态是更难的分布式问题”。
🔧 思考题 4(进阶)
“抽象升层,旧 guarantee 失效”——你说多集群让单集群的 guarantee 重演成跨集群麻烦。请类比第 2 章(裸机→容器)和第 3 章(命令式→声明式),说明”升层”在系统设计中是普遍现象,并给出”设计多层系统时要注意什么”的方法论。
【参考答案】 普遍现象:(1) 第 2 章:裸机时代”单机内进程隔离”由 OS 保证,到容器/多机,“跨机一致/隔离”要容器编排重新保证——升层后 OS 的 guarantee(单机)失效,K8s 重做跨机版;(2) 第 3 章:单机内”调用一个函数肯定执行”由程序计数器保证,到分布式”调一个服务可能丢/重/乱序”,要声明式+level-triggered 重做”可靠”;(3) 本章:单集群内 etcd 保证”状态一致/可 watch”,到多集群”跨集群一致”要联邦控制面+跨集群网络/存储重做。模式:每次把系统边界从”单机”推到”多机”再到”多集群”,下层的”一致性/隔离/可靠”保证都只在原边界内有效,升层后需在新边界内用新机制重建。方法论(设计多层系统):(a) 明确每层的 guarantee 边界:这层保证什么、不保证什么(如 K8s 保证单集群内,不保证跨集群);(b) 升层时主动重审 guarantee:哪条旧保证会失效?怎么在新层补(如单集群 Service 一致→跨集群要联邦/网格);(c) 别假设上层自动继承下层语义:Pod 同集群互通≠跨集群互通,要显式建跨层机制;(d) 用统一范式降低多层复杂度:K8s 用”声明式+控制循环”贯穿 Pod/集群/应用,减少每层的范式切换成本(第 14.7/22.8)。结论:多层系统的难度不在单层,在”层边界处的 guarantee 断裂”——设计者要盯着边界而非层内。这题把全书多个升层案例提炼成方法论,是系统设计者的高阶视角。
23.9 小结
- 多集群五推力(规模/故障域/合规/混合云/就近/隔离)是单集群麻烦的升层;
- 难点在独立控制面发散;Cluster API 把集群当 CRD 声明式造(K8s 范式用于自身);
- 联邦(Karmada)用 PropagationPolicy 分发应用+跨集群调度;与 GitOps/网格叠加;
- 一致性难题:跨集群网络/存储/身份/状态更难,有状态跨集群是老难题重演;
- 抽象升层,旧 guarantee 失效——设计多层系统要盯”层边界”而非层内;
- 五层声明式(CAPI→联邦→网格→GitOps→K8s)是同一脊椎的复利。
下一章讲大规模集群性能调优——万节点挑战。前面好几章埋了”etcd 写瓶颈""EndpointSlice 分片""watch 扇出”,这章把它们汇成一张”万节点怎么不崩”的作战图。