跨集群 L3 网络互联,让不同集群的 Pod 与 Service 直接互通
Submariner 是 CNCF Sandbox 项目(2021-04-28 进入沙箱,截至 2026 年 9 月仍未晋升 Incubating/Graduated),由 Red Hat 主导,采用 Apache-2.0 许可。它解决的是多集群场景中最底层的一个问题:让集群 A 的 Pod 能用 IP 直接访问集群 B 的 Pod 与 Service。
它工作在网络层(L3),与 CNI 无关(Calico、Cilium、Flannel、OVN-Kubernetes 都能配合),这是它与 Skupper 这类应用层方案最本质的区别。当前最新版本为 v0.24.1(2026-08-30),是一个安全修复版本(修掉了 WireGuard 默认 PSK 回退问题);项目仍是 0.x,但已在生产中使用,维护着 7 条发布分支的回移植。
方案 层次 跨集群 Pod IP 跨集群 Service 依赖
Submariner L3 IP 直接可达 clusterset.local DNS CNI 无关
Cilium ClusterMesh L3/L4 IP 直接可达 Global Service 必须用 Cilium
Skupper L7 不可达 代理转发(AMQP) 无
Karmada 的 ServiceImport API 不负责 提供发现 API 不提供数据面
一句话:Submariner 把多个集群的网络「压平」成一个平面,集群 A 里的 Pod 直接用集群 B 的 Pod IP 就能通信。代价是它要求两边地址空间能协调,以及网关节点必须能互通。
submariner-gateway DaemonSet,只调度到打了网关标签的节点,负责建立 IPsec/WireGuard 隧道
submariner-routeagent DaemonSet,跑在所有节点,把跨集群流量从节点转发到活动网关
submariner-globalnet 可选组件,处理 CIDR 重叠场景下的地址转换
submariner-lighthouse-* 服务发现(CoreDNS 插件 + lighthouse-agent)
submariner-operator 控制器,负责安装与协调上述组件
submariner-k8s-broker 只在 broker 集群部署,供各集群交换元数据
submariner-metrics-proxy 指标代理(监控用)
默认命名空间:submariner-operator(成员组件)与 submariner-k8s-broker(broker)。
Broker 的形态比较特殊 —— 它不是一个服务,而是一组 CRD + RBAC,所有集群的 Gateway Engine 都能读写这个集群的 API Server,通过里面的 Endpoint、Cluster 等对象互相发现对方。因此 Broker 集群的 API Server 必须对所有成员集群可达。
subctl 是官方推荐的部署入口,一个集群做 broker,其余集群 join:
# 安装 subctl
curl -Ls https://get.submariner.io | bash
# 1. 选一个集群作为 broker
subctl deploy-broker --kubeconfig cluster-a.config
# 会生成 broker-info.subm,后续 join 都靠它
# 2. 其余集群加入
subctl join broker-info.subm --kubeconfig cluster-b.config
subctl join broker-info.subm --kubeconfig cluster-c.config
# 3. 校验连通性(需要两个集群的 kubeconfig)
subctl verify --context cluster-a --tocontext cluster-b
# 4. 查看状态
subctl show all
subctl show networks
subctl show connections
subctl show gateways
subctl show endpoints
# 5. 排障与信息收集
subctl diagnose all
subctl gather
# 6. 导出服务供其它集群访问
subctl export service -n default nginx
# 7. 卸载 / broker 信息恢复
subctl uninstall
subctl recover-broker-info
subctl join 会顺带装上 Submariner Operator,并自动挑选一个 Worker 节点作为网关(--label-gateway 默认开启,即自动打标签并提示)。
不用 subctl 时,两个官方 chart 分别是 broker 端与成员端:
helm repo add submariner-latest https://submariner-io.github.io/submariner-charts/charts
# broker 集群
helm install submariner-k8s-broker submariner-latest/submariner-k8s-broker \
--create-namespace --namespace submariner-k8s-broker
# 成员集群
helm install submariner-operator submariner-latest/submariner-operator \
--create-namespace --namespace submariner-operator \
--set ipsec.psk="${SUBMARINER_PSK}" \
--set broker.server="${SUBMARINER_BROKER_URL}" \
--set broker.token="${SUBMARINER_BROKER_TOKEN}" \
--set broker.namespace=submariner-k8s-broker \
--set broker.ca="${SUBMARINER_BROKER_CA}" \
--set submariner.serviceDiscovery=true \
--set submariner.cableDriver=libreswan \
--set submariner.clusterId="${CLUSTER_ID}" \
--set submariner.clusterCidr="${CLUSTER_CIDR}" \
--set submariner.serviceCidr="${SERVICE_CIDR}" \
--set submariner.natEnabled="true"
关键 values:
ipsec.psk 集群间的预共享密钥,必须所有集群一致
submariner.cableDriver libreswan(默认) / wireguard / vxlan
broker.globalnet CIDR 重叠时置 true
submariner.natEnabled 网关之间是否存在 NAT
submariner.clusterId 集群数字 ID,broker 内唯一
submariner.clusterCidr Pod CIDR
submariner.serviceCidr Service CIDR
submariner.globalCidr Globalnet 使用的全局网段
注意 PSK 的键名是 ipsec.psk,不是 submariner.ceIPSecPSK —— 后者是 Mesh 方案里常见的误写。
网关节点通过节点标签手工指定,这是与其他组件最容易混淆的一点:
kubectl label node worker-1 submariner.io/gateway=true
# 查看哪些节点是网关
kubectl get nodes -l submariner.io/gateway=true
# MTU 问题时的应急注解(封装后大包被丢)
kubectl annotate node worker-1 submariner.io/tcp-clamp-mss=1400
一个集群可以标记多个网关节点做冗余,但同一时刻只有一个 Gateway Engine 处于活动状态,由 leader election 选出。活动网关失联后,另一个节点会赢得选举、重建 Endpoint,其它集群通过 broker 感知到新 Endpoint 并重新建隧道。
4500/UDP IPsec NAT-T,隧道封装端口(可用 --nattport 改成非标准端口)
4490/UDP NAT 发现端口(不可改),网关之间必须双向放行
4800/UDP VXLAN,集群内部节点与网关之间的隧道流量
ESP 协议 网关之间没有 NAT、直接可达时需要放行
8080/TCP 指标端口(按需)
如果网关之间是公网直连(无 NAT),放行 ESP 即可;一旦中间有 NAT,就退化为 4500/UDP 的 NAT-T。企业防火墙常常只放行 TCP,这是部署 Submariner 时最常见的阻塞点。
跨集群的 Service 发现基于 Multi-Cluster Services API(multicluster.x-k8s.io),必须显式导出:
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
name: nginx
namespace: default
导出后,其它集群可以用固定 DNS 名称访问:
nginx.default.svc.clusterset.local 普通 Service
pod-0.cluster-b.nginx.default.svc.clusterset.local headless Service 下的单个 Pod
ServiceImport 由 Lighthouse 内部创建,不需要人工干预;没有 ServiceExport 就没有 clusterset.local 记录。
如果两个集群的 Pod/Service CIDR 重叠,普通模式无法工作,需要启用 Globalnet 把重叠地址做一层转换:
subctl deploy-broker --globalnet
subctl join broker-info.subm --globalnet --globalnet-cidr-range 242.0.0.0/8
# 集群级出网 IP
kubectl get clusterglobalegressips -A
# 入向暴露单个 Service
kubectl get globalingressips -A
Globalnet 是补丁而不是等价替代:它引入额外的地址转换与 GlobalIngressIP 对象管理,排障复杂度明显上升,能重新规划 CIDR 就应该重新规划。
subctl diagnose deployment 会检查这一点。重叠时只能用 Globalnet,而 Globalnet 会带来额外 NAT 与对象管理成本。Endpoint 无法发布,集群加入/变更也不可见。因此 broker 集群要当生产组件对待,并定期执行 subctl recover-broker-info 备份 broker 信息。submariner.natEnabled,否则表现为隧道一直建不起来、subctl show connections 里连接状态异常。Endpoint,期间跨集群流量会中断,不要期望秒级无感切换。submariner.io/tcp-clamp-mss 注解,还可以在应用侧调小 MSS。ServiceExport 必须逐个命名空间显式创建,没有「自动导出整个集群」的开关。导出前 clusterset.local 一定解析失败,不要误判成 DNS 故障。vxlan 不加密,只适合可信网络;跨公网应使用 libreswan(IPsec)或 wireguard。选择 vxlan 又会引入 4800/UDP 的额外放行要求。kubectl — Kubernetes集群管理工具cilium — 自带 ClusterMesh 多集群网络能力calico — 常与 Submariner 配合的 CNIistio — 跨集群服务网格,可叠加使用karmada — 多集群应用分发,与 Submariner 互补helm — 用官方 chart 部署 broker 与 operator