4. 多集群 Service 暴露:Global Service 概念、ClusterIP 与 Headless Service 的跨集群访问、ExternalName 与 Multi-Cluster Service
在 Cilium ClusterMesh 的多集群拓扑中,Pod 网络已通过 Overlay 或 Native-Routing 实现互通,但 Kubernetes Service 的默认行为仍被限制在单个集群内。本章将深入剖析如何通过 Global Service 将 Service 边界扩展到多集群,并详细对比 ClusterIP、Headless Service、ExternalName 以及 Multi-Cluster Service API 在跨集群场景下的适用性与实现机制。
4.1 Global Service 概念与工作原理
Global Service 是 Cilium ClusterMesh 提供的核心抽象,它允许将一个 Kubernetes Service 的端点集合扩展到多个集群。其本质是在每个集群中创建一个同名的 Service,并通过 Cilium 的控制面同步机制,将远端集群的端点信息注入到本地集群的 EndpointSlice 中。
Global Service 的生效需要满足以下条件:
- 同名同命名空间: 参与 Global Service 的 Service 必须在所有集群中具有相同的名称和命名空间。
- ClusterMesh 已连接: 集群间必须通过 ClusterMesh 完成控制面与数据面的互联。
- Service 注解: 需要在 Service 上添加注解
io.cilium/global-service: "true"。
io.cilium/shared-service: "true" 注解,以允许本地集群的 Pod 通过 Service IP 访问本地端点,避免不必要的跨集群流量。
4.2 ClusterIP 的跨集群访问
在启用 Global Service 后,ClusterIP 类型的 Service 可以跨集群访问。客户端 Pod 只需访问本地集群的 Service ClusterIP,Cilium 的 eBPF 程序会根据后端端点列表(包含本地和远端)进行负载均衡。
| 特性 | 单集群 ClusterIP | Global ClusterIP |
|---|---|---|
| 端点来源 | 仅本地 EndpointSlice | 本地 + 远端 EndpointSlice |
| 负载均衡范围 | 本地 Pod | 所有集群的 Pod |
| 流量路径 | 节点内或节点间 | 可能经过跨集群隧道 |
| DNS 解析 | 返回本地 ClusterIP | 返回本地 ClusterIP(不变) |
| 故障转移 | 仅本地健康检查 | 跨集群健康检查与自动摘除 |
externalTrafficPolicy: Local,但这会限制跨集群负载均衡的效果。
4.2.1 配置示例
apiVersion: v1
kind: Service
metadata:
name: my-global-svc
namespace: production
annotations:
io.cilium/global-service: "true"
io.cilium/shared-service: "true"
spec:
type: ClusterIP
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
在集群 A 和集群 B 中分别应用此 YAML,确保两个集群中都有匹配 app: my-app 的 Pod 运行。Cilium 会自动合并端点。
4.3 Headless Service 的跨集群访问
Headless Service(clusterIP: None)在跨集群场景下具有特殊价值。它不提供 ClusterIP 和负载均衡,而是直接返回所有后端 Pod 的 IP 列表(DNS 记录)。在 Global Service 模式下,Headless Service 的 DNS 记录会包含来自所有集群的 Pod IP。
跨集群 Headless Service 的 DNS 解析行为:
- A 记录: 返回所有集群中匹配 Pod 的 IP 地址。
- SRV 记录: 返回包含端口和优先级的服务发现信息。
- Pod 就绪状态: 只有就绪的 Pod 才会被包含在 DNS 记录中。
apiVersion: v1
kind: Service
metadata:
name: my-statefulset-svc
namespace: production
annotations:
io.cilium/global-service: "true"
spec:
clusterIP: None
selector:
app: my-stateful-app
ports:
- port: 3306
targetPort: 3306
publishNotReadyAddresses: true 谨慎控制,或结合应用层的服务发现机制(如 Consul、etcd)进行分流。
4.4 ExternalName Service 与 Multi-Cluster Service
4.4.1 ExternalName Service 的跨集群局限
ExternalName Service 本质上是 DNS 级别的 CNAME 重定向,它不经过 Cilium 的 eBPF 数据面。在跨集群场景中,ExternalName 只能将流量引向一个外部的 DNS 名称,无法感知集群拓扑变化或实现负载均衡。
| 对比维度 | ExternalName | Global ClusterIP | Headless Global |
|---|---|---|---|
| 数据面参与 | 否(仅 DNS) | 是(eBPF) | 是(DNS + 直连) |
| 跨集群端点感知 | 无 | 自动同步 | 自动同步 |
| 负载均衡 | 依赖外部 DNS | Cilium 原生 | 客户端自行实现 |
| 典型用途 | 指向外部托管服务 | 无状态应用 | 有状态应用 |
4.4.2 Multi-Cluster Service API(MCS API)
Kubernetes 社区推出的 Multi-Cluster Service API(简称 MCS API)旨在标准化跨集群服务发现。Cilium ClusterMesh 原生支持 MCS API,提供了与 Global Service 互补的另一种抽象方式。
MCS API 的核心资源:
- ServiceExport: 标记一个 Service 需要被导出到其他集群。
- ServiceImport: 在其他集群中创建一个虚拟 Service,代表远端导出的服务。
4.4.3 使用 MCS API 的配置示例
在导出端集群创建 ServiceExport:
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
name: my-app-svc
namespace: production
spec: {}
# 无需 spec,只需声明导出即可
在导入端集群创建 ServiceImport:
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceImport
metadata:
name: my-app-svc
namespace: production
spec:
type: ClusterSetIP
ports:
- port: 80
protocol: TCP
4.5 跨集群 Service 选型决策
根据不同的应用场景,选择合适的跨集群 Service 暴露方式:
| 应用类型 | 推荐方式 | 理由 |
|---|---|---|
| 无状态 Web 服务 | Global ClusterIP | 自动负载均衡,无需修改应用代码 |
| 有状态数据库集群 | Global Headless | 客户端直接发现所有实例,自行实现读写分离 |
| 需要标准化跨云 | MCS API + ClusterSetIP | 厂商中立,便于多云迁移 |
| 指向外部系统 | ExternalName | 仅 DNS 重定向,不涉及跨集群数据面 |
| 需要保留客户端源 IP | Global ClusterIP + Local | 牺牲部分负载均衡能力,换取源 IP 透传 |
io.cilium/global-service: "true" 的同时,开启 Cilium 的监控指标(cilium monitor 或 Hubble),实时观察跨集群流量的分布与健康状态。