首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

探索基于隧道的 Kubernetes 跨集群通讯

伴随着k8s的大量使用,无论是基于应用隔离或者高可用,容灾的需要还是运维管理的需求,很多企业都会部署多个K8S集群。这就会导致有些应用依赖于其它k8s集群的微服务,需要从一个集群里的pod访问另外一个集群里的pod或者service。为了解决跨集群服务调用的问题,我们试验了一种基于隧道的方案,下面就让我们一起来体验一下吧。

作者:鲍盈海, 中国移动云能力中心软件开发工程师,专注于云原生领域。

环境要求:

01

单隧道单服务访问

先介绍一下最简单的场景,让集群A中的服务访问集群B中的服务,架构图如下:

集群A和集群B由一条隧道连接,隧道的左边是代理了隧道入口的service,隧道的右边是一个业务服务,我们在左边集群A中在宿主机上通过curl+ip的方式(或者在容器中通过域名的方式)访问集群B的业务服务。下面我们一起来实际操作一下。我们从右往左来部署服务。

1.先部署demo-service,这个服务是golang官网的demo : https://go.dev/doc/tutorial/web-service-gin, 将它打包成镜像后使用k8s来部署在集群B中充当业务服务,创建pod和svc的yaml文件如下 :

2. 创建隧道,我们使用ssh命令来创建一个ssh隧道,在clusterB上执行如下的命令:

其中8079是集群A上监听的端口,31080是集群B上监听的端口,也是demo-service的svc暴露出来的端口,后面root@[集群A的隧道入口机器IP]是集群A中的机器。需要注意的是集群A的机器的ssh必须开启网关转发功能,具体修改步骤是将/etc/ssh/sshd_config文件中的GatewayPorts改为yes,并重启sshd。

3. 我们还创建了一个tunnel-service的svc,这是一个没有selector的服务,目的是方便集群A中的服务来访问隧道。详细的yaml如下:

至此,在集群A中就可以通过隧道来访问集群B的服务了。但是目前这种方案还不适合在生产环境中使用,因为一般情况下跨集群之间因为安全、性能、成本等因素多个服务会复用一条隧道,而上面的方案中,一个服务独占了一条隧道,如果有多个demo-service服务则需要创建多个隧道。所以我们设计了单隧道多服务的方案。

02

单隧道多服务访问

单隧道多服务的实现原理是在隧道两头增加一个隧道的代理,隧道左端监听多个端口,用来区分集群A中服务要访问的集群B中的不同服务。并且将此信息告知隧道游段的代理,隧道右段代理根据此信息来转发给对应的ClusterB中的服务。架构图如下:

我们定义了一个配置文件,来描述隧道左侧监听的端口与隧道右侧服务映射的关系,如下:

03

关键代码列举

上面配置的功能是被隧道发送方和接收方共享的,所以在代码设计中做了三个module,分别是common(读取配置文件),receive(隧道右侧代理),send(隧道左侧代理)。目录结构如下:

其中三个go文件和go.mod文件如下:

common/config.go

common/go.mod

receive/main.go

receive/go.mod

send/main.go

send/go.mod

构建tunnel-service和tunnel-sned的dockerfile文件分别如下:

打包镜像的脚本可以参考如下:

最终我们打包了nexus.cmss.com:8086/cnp/tunnel/receive:v1.0.0和nexus.cmss.com:8086/cnp/tunnel/send:v1.0.0两个镜像。

04

部署实操

下面我们也来一起部署一下,同样是从右往左部署:

1.我们依然使用golang官网的demo : https://go.dev/doc/tutorial/web-service-gin, 作为demo-service,不同的是我们要创建两个。yaml文件如下:

然后我们需要造一点数据,来区分两个服务,在这个demo中支持创建数据,命令如下:

然后在浏览器中输入http://[集群B中宿主机IP]31050/albums

和http://[集群B中宿主机IP]:31051/albums来查看插入的数据是否生效。

2. 部署tunnel-receive服务,即隧道接收端的服务,其中namespace已经在第一步中创建了,yaml文件如下:

服务部署后,可以通过在clusterB上执行下面的命令来检查receive服务是否正常,注意此处已经在header中设置了X-Proxy-Condition。

3. 创建隧道,同单隧道单服务中的步骤,执行下面的命令

在集群A上执行下面的命令来检查隧道是否成功创建:

同样的我们还需要创建一个没有selector的svc来代理隧道的左边,yaml文件如下:

4. 部署tunnel-send服务,即隧道发送端的服务,yaml文件如下:

至此,已经全部部署结束,执行下面的命令测试一下:

或者在浏览器里访问上面的地址,结果如下:

05

结束语

以上我们通过ssh隧道实现了跨集群的访问,目前只是在demo的程度,要在正式环境中使用的话,还需要考虑整个通信的稳定可靠的问题,例如给隧道增加心跳,多条隧道做负载均衡等。实际在业界还有例如Submariner(https://submariner.io/)等开源项目能轻松提供跨集群的安全应用访问,大家可以进一步学习了解。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230204A06C2Z00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券