土法炼钢兴趣小组的算法知识备份

【Istio 控制面】多集群东西向发现扇出:Primary-Remote 与网络拓扑

文章导航

分类入口
networkkubernetes
标签入口
#istio#istiod#multicluster#eastwest-gateway#split-horizon-eds#locality#remote-secret

目录

前几篇把单集群内”watch → push”的机制钉死了。多集群把同一套机制的输入源从一个 K8s API Server 变成多个,输出端还要多一步”这个端点对当前代理是否直接可达”的判断。本文只回答控制面层面的两个机制问题:istiod 如何获得跨集群的服务发现输入;同一个逻辑 Service 的端点分布在不同网络时,EDS 推给某个代理的地址列表如何被重写。

不做 Istio vs 其他网格的多集群方案评选,不编造跨集群延迟数字——那需要具体拓扑下的实测,本篇不具备。

本文是「Istio 控制面内核」系列第 12 篇(共 16 篇)。→ 系列目录

版本锚定:Istio 1.30.3;官方多集群安装文档同期版本路径(istio.io/latest/docs/setup/install/multicluster/,Istio 1.30 系列)。


一、输入端:一个 istiod 如何 watch 多个 API Server

单集群时,istiod 的服务发现输入只有本集群 K8s API Server。多集群的 Primary-Remote 部署模型把输入端扩成多个:

  1. 生成一份远程访问凭证istioctl create-remote-secret),本质是把远程集群的 API Server 访问信息打包成一个 Kubernetes Secret。
  2. 把这个 Secret 应用到 primary 集群的 istiod 命名空间。istiod 读到这个 Secret 后,会像 watch 本地 API Server 一样,对远程集群的 API Server 建立 watch 连接,抓取该集群的 Service / Endpoint(对应 topology.istio.io/controlPlaneClusters 标注的远程集群关系)。
  3. 同名同命名空间的 Service 在不同集群上的端点会被合并进同一个逻辑 Service——对使用方(VirtualService、DestinationRule)来说,跨集群与否是透明的;对 istiod 内部来说,这个 Service 的 endpoint 列表现在混合了本地 Pod IP 与远程集群 Pod IP。

官方 Deployment Models 文档把这个约束写得很直接:多 primary 集群场景下,每个 primary 集群的配置来源仍是各自的 API Server,配置本身不跨集群同步——“两个集群上各自 apply 一份 VirtualService”这件事,Istio 不会替你保证一致,需要 CI/CD 或 GitOps 工具在配置分发层解决。这是多集群机制里第一个容易被低估的责任边界:服务发现是自动跨集群聚合的,配置分发不是。

flowchart TD
  subgraph c1 ["cluster1 (primary)"]
    api1["K8s API Server"]
    istiod["istiod"]
  end
  subgraph c2 ["cluster2 (remote)"]
    api2["K8s API Server"]
  end
  secret["remote secret<br/>(istioctl create-remote-secret)"]
  api1 --> istiod
  secret -.grants access.-> istiod
  istiod -->|watch| api2
  istiod --> merged["Merged Service:<br/>endpoints from cluster1 + cluster2"]

二、输出端:Split-Horizon EDS 按网络重写端点

合并出来的端点列表不能原样推给所有代理——如果两个集群之间没有 Pod 网络直连(不同 network),把远程集群的 Pod IP 直接塞进本地代理的 EDS 响应,代理连不上。Istio 的解法是 Split-Horizon EDS:对每个代理,按它所在的网络重写端点列表。

源码落点是 pilot/pkg/xds/endpoints/ep_filters.goEndpointsByNetworkFilter

// pilot/pkg/xds/endpoints/ep_filters.go(Istio 1.30.3,节选)
// EndpointsByNetworkFilter is a network filter function to support Split Horizon EDS - filter the endpoints based on the network
// of the connected sidecar. The filter will filter out all endpoints which are not present within the
// sidecar network and add a gateway endpoint to remote networks that have endpoints
// (if gateway exists and its IP is an IP and not a dns name).
func (b *EndpointBuilder) EndpointsByNetworkFilter(endpoints []*LocalityEndpoints) []*LocalityEndpoints {
    if !b.gateways().IsMultiNetworkEnabled() && (!features.EnableAmbientMultiNetwork || isSidecarProxy(b.proxy)) {
        // Multi-network is not configured (this is the case by default). Just access all endpoints directly.
        return endpoints
    }
    ...
    gateways := b.selectNetworkGateways(epNetwork, epCluster)
    ...
}

行为总结:

这就是”东西向网关”在控制面视角下的真实含义:它不是一个业务概念,而是 Split-Horizon EDS 用来替换跨网络端点的一个转发点。源码注释里还明确了一个历史遗留的边界情况:如果配置了多网络但没有部署东西向网关,Istio 仍会按同网络处理远程端点下发 EDS,实践中大概率因为 Pod 不可达而失败——这是一个已知的、故意不改的历史行为,因为改动可能破坏已有部署。

sequenceDiagram
  participant Pilot as istiod (EndpointBuilder)
  participant Sidecar as Sidecar on network1
  Note over Pilot: Merged endpoints: network1 pods + network2 pods
  Pilot->>Pilot: EndpointsByNetworkFilter(endpoints)
  Pilot->>Pilot: network2 endpoints -> selectNetworkGateways(network2)
  Pilot->>Sidecar: EDS response: network1 pod IPs (as-is) + network2 gateway IP (rewritten)

三、网络与地域标签:控制面如何知道谁在哪个网络

Split-Horizon EDS 依赖两个输入才能工作:代理属于哪个网络目标端点属于哪个网络。Istio 用统一的资源标签解决:

Locality(地域)负载均衡是独立的另一套机制,不是 Split-Horizon EDS 的一部分:它按 region/zone(以及可选的 subzone)标签给端点分优先级,让流量优先打到同 locality 的实例;多集群场景下,如果不同集群被打上不同 locality,流量会自然倾向本集群,除非显式关闭 locality 负载均衡或本地实例不健康触发故障转移。这一层只影响权重排序,不影响”这个端点是否可达”——可达性判断始终是 Split-Horizon EDS 的职责。


四、失败模式:控制面视角

多集群把单集群里”istiod 挂了”的故障域,变成了”哪个集群的哪个依赖挂了”的组合问题:

故障点 控制面表现 影响范围
远程集群 API Server 不可达 istiod 对该远程集群的 watch 连接失败/重试;远程集群的端点从合并结果中消失 该远程集群的实例不再出现在任何代理的 EDS 里,不是进程崩溃,是端点列表变短
remote secret 过期/被吊销 同上,鉴权失败导致 watch 无法建立 与 API Server 不可达表现类似,需要查 istiod 日志区分网络问题还是鉴权问题
东西向网关不可用 Split-Horizon EDS 仍会把远程网络端点重写为该网关地址,因为 EDS 层不做网关健康探测 客户端拿到”看似合法”的网关端点,实际连接失败或超时,需要靠 Envoy 侧的健康检查/outlier 摘除
多 primary 配置漂移 控制面无检测机制 两个集群上同名 VirtualService 内容不一致,行为取决于流量落在哪个集群的数据面,且不会有任何”配置冲突”告警

后两行是本篇要强调的机制边界:Split-Horizon EDS 只负责”地址怎么写”,不负责”地址是否健康”;多 primary 的配置一致性,Istio 完全不管,责任在运维流程。


五、争论与开放问题

争论 A B
Primary-Remote vs 多 Primary 单一配置源,运维简单,但 primary 集群是单点 多 primary 高可用,但配置一致性完全靠外部流程兜底
关闭东西向网关、走扁平网络直连 少一跳、少一个故障域 放弃了 Split-Horizon EDS 的隔离收益,网络必须真正互通且信任模型要延伸到跨集群
Split-Horizon EDS 不做网关健康探测 保持 EDS 层职责单一,健康判断留给既有的 outlier/健康检查机制复用 网关本身的可用性只能靠数据面事后摘除,没有控制面前置探测

开放问题:多集群 EDS 合并 + Split-Horizon 重写叠加在一起后,第 10 篇讨论的 debounce/端点抖动问题会不会被放大——例如远程集群一次大规模滚动发布,是否会被本地 istiod 当作一次需要重算 push context 的 Full 事件、进而影响到与该远程集群完全无关的本地代理?这需要具体拓扑下的实测(多集群 + 端点 churn 注入),本篇不给未跑过的结论。


六、参考资料

规范 / 官方文档(A)

源码(A)

站内对照

实验台账


七、小结

  1. 服务发现跨集群自动聚合,配置分发不会:remote secret 让 istiod 跨集群 watch 端点,但多 primary 的配置一致性完全是运维流程的责任。
  2. Split-Horizon EDS 是一个地址重写层:同网络端点原样下发,跨网络端点被替换成东西向网关地址,Envoy 对此无感知。
  3. 网络标签决定 EDS 重写是否触发;Locality 标签只影响优先级排序——两者是独立的机制,不要混为一谈。
  4. 东西向网关的健康状态不在 EDS 层把关,网关不可用要靠数据面自身的健康检查/outlier 兜底。

系列目录 · 上一篇:NACK / Warming 责任 · 下一篇:Ambient:ztunnel / waypoint

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .