k8s跨集群通讯项目-Submariner

文章目录

  • 前言
  • 一、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的方式安装
  • 五、部署测试应用验证跨集群通讯
  • 六、后续
    • 6.1 ACM 2.5 2022/6/9 正式GA,可以支持GlobalNet
    • 6.2 GlobalNet
      • 集群范围的全局出口IP
      • Namespace范围的全局出口IP
      • Service 的全局入口 IP
  • 总结


前言

伴随着k8s的大量使用,无论是基于应用隔离或者高可用,容灾的需要还是运维管理的需求,很多企业都会部署多个K8S集群。 这就会导致有些应用依赖于其它k8s集群的微服务,需要从一个集群里的pod访问另外一个集群里的pod或者service。
为了解决跨集群服务调用的问题,市场上出现了很多开源项目来解决这个问题。有机遇CNI的,有与CNI无关的机遇集群间的,有基于service mesh的。本文重点介绍一个在集群间建立的开源方案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 提供服务发现功能。
k8s跨集群通讯项目-Submariner_第1张图片

2.1​ Submariner重要组件

  • 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 的集群的互连。(可选)

2.2 Broker

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恢复后,控制平面的组件会自动重新同步和更新数据。

2.3 服务发现

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是开源软件项目,在企业内使用开源软件时,服务是一个关键,有保障的服务才会提供及时的安全补丁,遇到问题时有专家提供服务。 红帽积极参与Submariner社区的开发,并在多集群管理组件ACM - Advanced Cluster Management for Kubenets提供 Submariner Addon来帮助使用 OCP - Openshift Container Platform的用户来实现跨集群的通讯。
k8s跨集群通讯项目-Submariner_第2张图片
在ACM里包含了Submariner的operator,安装配置过程非常简单,下面以我在AWS上的两个集群为例介绍我的测试过程。

4.1 测试环境

使用OCP4.9, ACM2.4
两个集群:

  • local-cluster (ACM hub集群本身也被作为被管集群)
  • managed-cluster
    k8s跨集群通讯项目-Submariner_第3张图片
    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

managed cluster

clusterNetwork: 10.132.0.0/14
serviceNetwork: 172.31.0.0/16

4.2 在ACM控制台创建cluterset

  1. 在ACM控制台 Infrastructure -> Clusters-> Cluster Sets 点击 Create
    clusterset按钮
    k8s跨集群通讯项目-Submariner_第4张图片

  2. 输入clusterset名称
    k8s跨集群通讯项目-Submariner_第5张图片

  3. 添加集群到clusterset
    k8s跨集群通讯项目-Submariner_第6张图片
    k8s跨集群通讯项目-Submariner_第7张图片

clusterset创建成功后,broker安装在ACM 的hub cluster中 。

4.3 安装Submariner add-ons

  1. 点击刚创建的clusterset,在Submariner add-ons里安装
    k8s跨集群通讯项目-Submariner_第8张图片

  2. 选择在哪些集群上安装addon,在这些集群中会安装broker以外的其它组件,这些组件安装在这些集群的submariner-operator namespace中
    k8s跨集群通讯项目-Submariner_第9张图片
    k8s跨集群通讯项目-Submariner_第10张图片
    k8s跨集群通讯项目-Submariner_第11张图片
    安装完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 Gateway

4.4 用命令行CLI的方式安装

本节未做细致整理,大致的步骤和命令供参考,详细步骤参见官方文档

  1. 在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

  1. 在每一个被管集群的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
  1. 把被管集群集群加入到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
  1. 部署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
  1. 检查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读历史数据显示在页面上。
k8s跨集群通讯项目-Submariner_第12张图片

在此示例中,我们使用 Red Hat Advanced Cluster Management 将guestbook前端和redis-leader服务部署到local-cluster. 然后我们将redis-follower服务部署到managed-cluster. 为了使这个应用程序能够工作,redis-leader服务和redis-follower服务应该能够相互访问,所以我们使用serviceexports.multicluster.x-k8s.io API 将它们导出到每个被管集群。

  1. 登录到Red Hat Advanced Cluster Management hub集群的控制台,导航到Manage applications在Application页面,点击 Create application

  2. 输入应用的名称和namespace的名称

  3. 选择 Git repository

  4. 选择应用的git url, 比如 https://github.com/aarenw/acm-demo-app

  5. Branch 选择main path 选择 guestbook
    k8s跨集群通讯项目-Submariner_第13张图片

  6. guestbook web前端部署到local-cluster,在这里选择 Deploy on local cluster ,其余保持默认值
    k8s跨集群通讯项目-Submariner_第14张图片

  7. 部署成功可以看到cluster resource的状态全部时绿色,资源的拓扑图可以看到每个资源的状态和属性。 注意可能存在一下问题:

  • 镜像库用的是gcr.io ,如果不能直接访问,需要下载后推送到你的集群可以访问的镜像库
  • pod使用了80端口,可能导致部署不成功,可以给所在namespace的default serviceaccount 添加scc来解决
  • 记得fork这个git修改route.yaml里的your-ocp-cluster-name 和your-ocp-cluster-domain , 否则route不可访问

k8s跨集群通讯项目-Submariner_第15张图片

k8s跨集群通讯项目-Submariner_第16张图片

  1. 重复2~7, 部署redis-leader, 在第5步里path选择 redis-leader
    k8s跨集群通讯项目-Submariner_第17张图片

k8s跨集群通讯项目-Submariner_第18张图片

k8s跨集群通讯项目-Submariner_第19张图片

  1. 重复2~7, 部署redis-follower 到managed-cluster, 第5步里选择redis-follower, 第6步选择 Deploy application resources only on clusters matching specified labels , Label输入name , Value 输入managed-cluster
    k8s跨集群通讯项目-Submariner_第20张图片

k8s跨集群通讯项目-Submariner_第21张图片

k8s跨集群通讯项目-Submariner_第22张图片

  1. 访问guestbook web 前端route的url,可以发现应用以及能够正常访问
    k8s跨集群通讯项目-Submariner_第23张图片

  2. 查看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
....
  1. 在两个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.27           6379/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.63           6379/TCP   17m   app=redis,role=follower,tier=backend

六、后续

6.1 ACM 2.5 2022/6/9 正式GA,可以支持GlobalNet

6.2 GlobalNet

默认情况下,Submariner 的一个限制是它不处理跨集群重叠的 CIDR(ServiceCIDR 和 ClusterCIDR)。每个集群必须使用不同的 CIDR。 为了支持连接集群中的重叠 CIDR,Submariner 有一个名为 Global Private Network 的组件 Globalnet ( globalnet)。这个 Globalnet 是一个虚拟网络,专门解决具有重叠CIDR的多集群通讯的问题。每个集群在部署时都从这个虚拟全局专用网络中获得一个子网,配置为新的集群参数GlobalCIDR(例如 242.0.0.0/8)。用户还可以手动为每个集群指定 GlobalCIDR加入Broker。

集群范围的全局出口IP

默认每个集群分配8个IP,用于在访问外部集群时使用,用资源 ClusterGlobalEgressIP 表示,数量可以配置。

Namespace范围的全局出口IP

通过创建 GlobalEgressIP 可以为namespace创建访问外部cluster时使用的EgressIP,它可以被namespace的所有pod或者自定pod使用。 GlobalEgressIP优先于ClusterGlobalEgressIP

Service 的全局入口 IP

导出ClusterIP类型的服务会自动从全局 CIDR 分配一个全局 IP 用于作为被访问的入口IP。对于Headless service,每个后备 pod 都分配有一个用于入口和出口的全局 IP。但是,如果后备 pod 与一个GlobalEgressIP 匹配,则其分配的 IP 将用于出口。

路由和 iptable 规则配置为使用相应的全局 IP 进行入口和出口。所有地址转换都发生在集群的活动的Gateway节点上。
k8s跨集群通讯项目-Submariner_第24张图片
k8s跨集群通讯项目-Submariner_第25张图片


总结

通过测试发现通过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 文档

你可能感兴趣的:(kubernetes,云原生,网络,服务发现,gateway)