痛点:多集群互通的现实困境
随着业务规模扩大,单一 Kubernetes 集群已难以满足需求。多云部署、异地容灾、环境隔离都催生了多集群架构。但问题随之而来:集群 A 的 Pod 如何访问集群 B 的 Service?
传统方案要么走公网 + LoadBalancer(成本高、延迟大),要么手动维护 VPN + DNS(运维复杂、易出错)。社区涌现了三款主流方案:Submariner、Skupper、Cilium ClusterMesh。本文基于生产实践,给出选型建议。
方案对比:三大工具核心差异
| 特性 | Submariner | Skupper | Cilium ClusterMesh |
|---|---|---|---|
| 网络层 | L3 隧道(IPsec/WireGuard) | L7 应用层代理 | L3 eBPF 直连 |
| CNI 依赖 | 兼容主流 CNI | CNI 无关 | 必须 Cilium |
| Service 发现 | ServiceExport CRD | 自动 Service 镜像 | 原生 Service 同步 |
| 安装复杂度 | 中等(需 Broker) | 低(纯应用层) | 高(需统一 CNI) |
| 性能 | 中等(隧道开销) | 较低(7 层代理) | 最优(eBPF 直通) |
| 适用场景 | 异构 CNI 多集群 | 轻量跨集群通信 | Cilium 统一环境 |
实操步骤:三种方案快速部署
方案一:Submariner — 异构 CNI 的通用解
Submariner 通过 Broker 集群协调多个成员集群,建立 IPsec/WireGuard 隧道。
# 1. 安装 subctl CLI
curl -Ls https://get.submariner.io | bash
export PATH=$PATH:~/.local/bin
# 2. 在 Broker 集群部署(通常选一个集群充当)
subctl deploy-broker --kubeconfig kubeconfig-broker
# 3. 将成员集群加入
subctl join --kubeconfig kubeconfig-cluster-a broker-info.subm \
--clusterid cluster-a --natt=false
subctl join --kubeconfig kubeconfig-cluster-b broker-info.subm \
--clusterid cluster-b --natt=false
# 4. 导出 Service 供跨集群访问
kubectl --kubeconfig kubeconfig-cluster-a apply -f - <<EOF
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
name: my-service
namespace: default
EOF
# 5. 在 cluster-b 通过 clusterset 域名访问
# my-service.default.svc.clusterset.local
方案二:Skupper — 零 CNI 依赖的轻量方案
Skupper 基于 AMQP 协议在应用层建立 Virtual Application Network,无需改动网络层。
# 1. 安装 Skupper CLI
curl https://skupper.io/install.sh | sh
# 2. 在 cluster-a 初始化
kubectl config use-context cluster-a
skupper init --site-name cluster-a
# 3. 生成连接令牌
skupper token create cluster-a-token.yaml
# 4. 在 cluster-b 连接
kubectl config use-context cluster-b
skupper init --site-name cluster-b
skupper link create cluster-a-token.yaml
# 5. 暴露 Service
kubectl config use-context cluster-a
skupper expose deployment/my-app --port 8080
# cluster-b 自动获得 my-app Service,直接访问
方案三:Cilium ClusterMesh — 性能最优解
如果所有集群都使用 Cilium CNI,ClusterMesh 提供原生级别的跨集群通信。
# 前提:所有集群已安装 Cilium,且 Pod CIDR 不重叠
# 1. 启用 ClusterMesh
cilium clustermesh enable --context cluster-a
cilium clustermesh enable --context cluster-b
# 2. 建立连接
cilium clustermesh connect --context cluster-a \
--destination-context cluster-b
# 3. 验证状态
cilium clustermesh status --context cluster-a
# 4. 创建 Global Service(两端都可访问)
kubectl --context cluster-a annotate service my-service \
service.cilium.io/global="true"
三个常见坑
坑一:Pod CIDR 冲突导致路由黑洞
现象:跨集群访问时丢包或路由到本地。
原因:两个集群的 Pod CIDR 重叠(如都用默认 10.244.0.0/16)。
解决: - 部署前规划 CIDR,每个集群使用独立网段 - Submariner 支持 Globalnet 做 NAT 转换,但会增加复杂度
# 集群规划示例
cluster-a: Pod CIDR 10.1.0.0/16, Service CIDR 172.21.0.0/16
cluster-b: Pod CIDR 10.2.0.0/16, Service CIDR 172.22.0.0/16
坑二:防火墙阻断隧道端口
现象:subctl diagnose 报 Gateway 连接失败。
原因:云厂商安全组未放行隧道端口。
解决:
# Submariner 需要放行的端口
# IPsec: UDP 500, 4500
# WireGuard: UDP 4800 (默认)
# VXLAN: UDP 4800
# AWS 安全组示例
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol udp --port 4500 \
--source-group sg-yyy
坑三:Skupper 高流量下性能瓶颈
现象:跨集群调用延迟突增,Skupper Router Pod CPU 飙高。
原因:Skupper 是 L7 代理,每个请求都经过 Router,高 QPS 场景成瓶颈。
解决:
- 增加 Router 副本数:skupper update --routers 3
- 高性能需求切换到 Submariner 或 ClusterMesh
生产选型建议
| 场景 | 推荐方案 |
|---|---|
| CNI 异构(如 Calico + Flannel 混用) | Submariner |
| 快速验证 / 开发测试环境 | Skupper |
| 全 Cilium 环境追求极致性能 | ClusterMesh |
| 跨云厂商(AWS + 阿里云) | Submariner + WireGuard |
| 只需少量 Service 互通 | Skupper(最简单) |
总结
多集群服务发现没有银弹。Submariner 胜在通用性,Skupper 胜在简单,Cilium ClusterMesh 胜在性能。选型核心看三点:
- CNI 是否统一 — 统一 Cilium 就上 ClusterMesh
- 性能要求 — 高 QPS 排除 Skupper
- 运维复杂度容忍度 — 怕麻烦先试 Skupper
生产环境建议先在非关键业务验证,重点监控跨集群延迟和隧道稳定性。多集群是趋势,选对工具事半功倍。