- 前言
- 一、Submariner功能
- 二、架构
- 2.1 Submariner重要组件
- 2.2 Broker
- 2.3 服务发现
- 三、术语和概念
- 四、测试Submariner安装
- 4.1 测试环境
- local cluster
- managed cluster
- 4.2 在ACM控制台创建cluterset
- 4.3 安装Submariner add-ons
- 4.4 用命令行CLI的方式安装
- 五、部署测试应用验证跨集群通讯
- 总结
前言
伴随着k8s的大量使用,无论是基于应用隔离或者高可用,容灾的需要还是运维管理的需求,很多企业都会部署多个K8S集群。 这就会导致有些应用依赖于其它k8s集群的微服务,需要从一个集群里的pod访问另外一个集群里的pod或者service。
为了解决跨集群服务调用的问题,市场上出现了很多开源项目来解决这个问题。有机遇CNI的,有与CNI无关的机遇集群间vpn的,有基于service mesh的。本文重点介绍一个在集群间建立vpn的开源方案Submariner。
Submariner 支持Pod 和服务在不同 Kubernetes 集群中的之间直接通讯,无论是在本地还是在公有云中。 Submariner 是完全开源的,设计旨在与网络插件 (CNI) 无关。 Submariner 是一个基于代理的集中式架构,该代理收集有关集群配置的信息并发送回参数以[供使用]。
本文的参考资料连接
Submariner开源项目官网
Demo App
Blog: Connecting managed clusters with Submariner in Red Hat Advanced Cluster Management for Kubernetes
Redhat Submariner 文档
一、Submariner功能
跨集群建立3层的网络连接,连接通道可以是加密的或者不加密的。
跨集群的服务发现
subctl, 命令行工具用来简化部署和管理
支持CIDRs重叠的的集群间通讯,两个集群的pod地址,service地址段重复。
Submariner 将连接的集群之间的网络扁平化,并实现集群间Pod和服务的IP可达性。 Submariner 还通过 Lighthouse 提供服务发现功能。
-
Gateway Engine: 网关引擎组件部署在每个参与的集群中,负责建立到其他集群的安全隧道。为了保持高可用,可以部署多个网关引擎,算法保证有一个active,其它的standby。 网关引擎是一个pluggable的架构,其负责建立隧道的组件可以替换
- IPsec , 通过 Libreswan 实现. 默认插件.
- WireGuard (via the wgctrl library).
- 不加密隧道, implementation using VXLAN.
活动的网关引擎组向broker提供cluster 和endpoint的信息
-
Route Agent: 将跨集群流量从节点路由到活动的网关引擎(Gateway Engine)。
-
Broker: 促进网关引擎之间的元数据交换,使它们能够相互发现。
-
Service Discovery: 提供跨集群服务的发现。Lighthouse 项目为 Submariner 连接的 Kubernetes 集群提供 DNS 发现。 Lighthouse 实现了 Kubernetes Multi-Cluster Service APIs。
-
Globalnet Controller: 处理具有重叠 CIDR 的集群的互连。(可选)
Broker 是一个 API,所有参与的集群都可以访问,其中两个对象通过 .submariner.io 中的 CRD 进行交换:
- Cluster:参与集群的静态信息,比如pod和service的 CIDR。
- Endpoint:包含集群中活动网管引擎的相关信息,比如IP。
Broker 必须部署在一个 Kubernetes 集群上,该集群的 API server必须可以被其它Kubernetes集群访问。 它可以是专用集群,也可以是连接的集群之一。
Broker本质上是一个CRD集合,保存在集群的ETCD数据库里。Broker也定义了一个ServiceAccount和相关的BRAC组件,让submariner组件安全的访问broker API。 Broker没有pod或者service
Broker的可用性不会影响数据链路的通信,控制平面组件将无法向其他集群发布新信息或更新信息,也无法从其他集群了解新信息或更新信息。在broker恢复后,控制平面的组件会自动重新同步和更新数据。
Lighthouse DNS维护一个额外的DNSserver负责域clusterset.local的解析。k8s 的coredns会把clusterset.local后缀的域名请求forward到lighthouse DNS, Lighthouse DNS会利用缓存中的ServiceImport resources来解析,如果记录存在就返回记录,不存在就返回NXDOMAIN。
When a single Service is deployed to multiple clusters, Lighthouse DNS server prefers the local cluster first before routing the traffic to other remote clusters in a round-robin fashion.
- ClusterSet 一组两个或多个高度互信的集群,它们之间共享服务。在集群集中,相同名称的所有命名空间都被认为是相同的命名空间。
- ServiceExport(CRD) - 用于指定要在集群集中公开服务。如果多个集群从同一个命名空间导出一个同名服务,它们将被识别为一个逻辑服务。
- ServiceExports 必须由用户在每个集群中以及服务所在的命名空间内显式创建,以表明该服务应该对集群集中的其他集群可见和可发现。ServiceExport可以手动或通过命令subctl export创建对象。
- 当一个服务被导出时,它就可以被访问为..svc.clusterset.local.
- 对于无头服务,单个 Pod 可以作为....svc.clusterset.local. 必须是有效的DNS-1123 标签
- ServiceImport(CRD) - 每个集群中的多集群服务的表示。由 Lighthouse 在内部创建和使用,不需要任何用户操作。
Submariner是开源软件项目,在企业内使用开源软件时,服务是一个关键,有保障的服务才会提供及时的安全补丁,遇到问题时有专家提供服务。 红帽积极参与Submariner社区的开发,并在多集群管理组件ACM - Advanced Cluster Management for Kubenets提供 Submariner Addon来帮助使用 OCP - Openshift Container Platform的用户来实现跨集群的通讯。
在ACM里包含了Submariner的operator,安装配置过程非常简单,下面以我在AWS上的两个集群为例介绍我的测试过程。
使用OCP4.9, ACM2.4
两个集群:
- local-cluster (ACM hub集群本身也被作为被管集群)
- managed-cluster
ACM2.4的Submariner还不包含Globalnet组件,需要在即将发布2.5里包含。因此需要连个集群的clusterNetwork和serviceNetwork上不要重叠。
在对应的集群用下面的命令可以查看当前集群的clusterNetwork,serviceNetwork 的CIDR
oc get network cluster -o json -o jsonpath='clusterNetwork: {.spec.clusterNetwork[*].cidr}{"n"}serviceNetwork: {.spec.serviceNetwork[*]}{"n"}'
local cluster
clusterNetwork: 10.128.0.0/14
serviceNetwork: 172.30.0.0/16
clusterNetwork: 10.132.0.0/14
serviceNetwork: 172.31.0.0/16
-
在ACM控制台 Infrastructure -> Clusters-> Cluster Sets 点击 Create
clusterset按钮
-
输入clusterset名称
-
添加集群到clusterset
clusterset创建成功后,broker安装在ACM 的hub cluster中 。
4.3 安装Submariner add-ons-
点击刚创建的clusterset,在Submariner add-ons里安装
-
选择在哪些集群上安装addon,在这些集群中会安装broker以外的其它组件,这些组件安装在这些集群的submariner-operator namespace中
安装完add-on后,operator会自动选择Gateway的节点,可用一下命令在各cluster里查看组件状态和Gateway信息。
oc -n submariner-operator get pods oc get node --selector=submariner.io/gateway=true -o wide oc -n submariner-operator describe Gateway4.4 用命令行CLI的方式安装
本节未做细致整理,大致的步骤和命令供参考,详细步骤参见官方文档
- 在hub server上创建 ManagedClusterSet
cat << EOF | kubectl apply -f - apiVersion: cluster.open-cluster-management.io/v1beta1 kind: ManagedClusterSet metadata: name: submarinerset EOF
会创建submarinerset-broker的namespace,并部署broker
oc get crds -n submarinerset-broker |grep -iE ‘submariner|multicluster.x-k8s.io’
查看哪些cluster加入到broker
oc get clusters.submariner.io -n submarinerset-broker
- 在每一个被管集群的namespace里创建 SubmarinerConfig资源来准备sumariner集群环境
For local-cluster:
cat << EOF | oc apply -f -
apiVersion: submarineraddon.open-cluster-management.io/v1alpha1
kind: SubmarinerConfig
metadata:
name: submariner
namespace: local-cluster
spec: {}
EOF
For managed-cluster:
cat << EOF | oc apply -f -
apiVersion: submarineraddon.open-cluster-management.io/v1alpha1
kind: SubmarinerConfig
metadata:
name: submariner
namespace: managed-cluster
spec: {}
EOF
- 把被管集群集群加入到managedclusterset
oc label managedclusters local-cluster "cluster.open-cluster-management.io/clusterset=submarinerset" --overwrite oc label managedclusters managed-cluster "cluster.open-cluster-management.io/clusterset=submarinerset" --overwrite
- 部署submariner到被管节点
cat << EOF | oc apply -f -
apiVersion: addon.open-cluster-management.io/v1alpha1
kind: ManagedClusterAddOn
metadata:
name: submariner
namespace: local-cluster
spec:
installNamespace: submariner-operator
EOF
cat << EOF | oc apply -f -
apiVersion: addon.open-cluster-management.io/v1alpha1
kind: ManagedClusterAddOn
metadata:
name: submariner
namespace: managed-cluster
spec:
installNamespace: submariner-operator
EOF
- 检查addon的部署状态
oc -n local-cluster get managedclusteraddons submariner -o yaml oc -n managed-cluster get managedclusteraddons submariner -o yaml
- 在local-cluster集群上
oc -n submariner-operator get pods oc get node --selector=submariner.io/gateway=true -o wide oc -n submariner-operator describe Gateway五、部署测试应用验证跨集群通讯
我用一个客户留言簿示例程序来验证被管集群间的通讯。
我在测试过程中fork了这个项目放在自己的项目里这样方便修改。
此示例中的应用程序包含guestbook Web前端,redis-leader service用于存储和redis-follower service存储备份。新的留言guestbook写入redis leader数据库,redis-follower从redis-leader同步数据,guestbook写完数据后从redis-follower读历史数据显示在页面上。
在此示例中,我们使用 Red Hat Advanced Cluster Management 将guestbook前端和redis-leader服务部署到local-cluster. 然后我们将redis-follower服务部署到managed-cluster. 为了使这个应用程序能够工作,redis-leader服务和redis-follower服务应该能够相互访问,所以我们使用serviceexports.multicluster.x-k8s.io API 将它们导出到每个被管集群。
-
登录到Red Hat Advanced Cluster Management hub集群的控制台,导航到Manage applications在Application页面,点击 Create application
-
输入应用的名称和namespace的名称
-
选择 Git repository
-
选择应用的git url, 比如 https://github.com/aarenw/acm-demo-app
-
Branch 选择main path 选择 guestbook
-
guestbook web前端部署到local-cluster,在这里选择 Deploy on local cluster ,其余保持默认值
-
部署成功可以看到cluster resource的状态全部时绿色,资源的拓扑图可以看到每个资源的状态和属性。 注意可能存在一下问题:
- 镜像库用的是gcr.io ,如果不能直接访问,需要下载后推送到你的集群可以访问的镜像库
- pod使用了80端口,可能导致部署不成功,可以给所在namespace的default serviceaccount 添加scc来解决
- 记得fork这个git修改route.yaml里的your-ocp-cluster-name 和your-ocp-cluster-domain , 否则route不可访问
- 重复2~7, 部署redis-leader, 在第5步里path选择 redis-leader
- 重复2~7, 部署redis-follower 到managed-cluster, 第5步里选择redis-follower, 第6步选择 Deploy application resources only on clusters matching specified labels , Label输入name , Value 输入managed-cluster
-
访问guestbook web 前端route的url,可以发现应用以及能够正常访问
-
查看guestbook的deployment 文件, pod 通过环境变量访问redis-local 和redis-follower, 无论本地还是远程都是访问serviceexports的域名。
....
env:
- name: GET_HOSTS_FROM
value: env
- name: REDIS_LEADER_SERVICE_HOST
value: redis-leader.guestbook.svc.clusterset.local
- name: REDIS_FOLLOWER_SERVICE_HOST
value: redis-follower.guestbook.svc.clusterset.local
....
- 在两个cluster上分别查看serviceexports, serviceimport以及service,可以发现在cluster里可以看到本地或者远程的导出的服务,所有serviceimport都指向service的IP,也就是说无论这个service在本地还是远程都一个通过serviceimport访问,这样简化了应用部署,提高部署灵活性。
- 在local-cluster
$ oc get serviceexports -n guestbook NAME AGE redis-leader 16m $ oc get serviceimport -n submariner-operator NAME TYPE IP AGE redis-follower-guestbook-managed-cluster ClusterSetIP ["172.31.221.63"] 9m16s redis-leader-guestbook-local-cluster ClusterSetIP ["172.30.56.27"] 19m $ oc get service redis-leader -n guestbook -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR redis-leader ClusterIP 172.30.56.276379/TCP 24m app=redis,role=leader,tier=backend
- on managed-cluster
$ oc get serviceexports -n guestbook NAME AGE redis-follower 16m $oc get serviceimport -n submariner-operator NAME TYPE IP AGE redis-follower-guestbook-managed-cluster ClusterSetIP ["172.31.221.63"] 16m redis-leader-guestbook-local-cluster ClusterSetIP ["172.30.56.27"] 26m $ oc get service -n guestbook -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR redis-follower ClusterIP 172.31.221.636379/TCP 17m app=redis,role=follower,tier=backend
总结
通过测试发现通过Red Hat ACM多集群管理组件,不仅可以轻松管理多集群的生命周期,应用部署,通过Submariner addon更是轻松提供了跨集群的安全应用访问,简单易用,期待ACM2.5版本的Submariner功能正式GA,并提供Globalnet功能。
本文的参考资料连接:
Submariner开源项目官网
Demo App
Blog: Connecting managed clusters with Submariner in Red Hat Advanced Cluster Management for Kubernetes
Redhat Submariner 文档



