青云QingCloud
作者青云QingCloud2021-01-02 20:22
技术经理, 青云QingCloud

Porter 如何帮助本来生活在 K8s 物理环境暴露集群服务

字数 7145阅读 276评论 0赞 0

1 公司简介

本来生活网创办于 2012 年 7 月,致力于改善食品安全现状、倡导健康生活方式。凭借七年来在生鲜领域的不断探索与创新,已发展成为中国生鲜新零售的开拓者与领导者。

2 技术现状

基础设施

  • 部署在 IDC 机房
  • 拥有 100 多台物理机
  • 虚拟化部署

存在的问题

  • 物理机 95% 以上的占用率
  • 相当多的资源闲置
  • 应用扩容比较慢

3 迁移到 K8s

基于以上情况,我们考虑逐步把生产环境从虚拟化迁移到 K8s 上,这样做的好处有以下几点:

  • 提高资源的利用率
  • 使应用能快速扩容
  • 降低运维人员工作复杂度

迁移会带来很大的时间成本,因此我们考虑使用 KubeSphere 作为底层容器平台,而我们在其之上进行二次开发,这样可以帮助我们节省很多开发时间。

4 如何暴露集群

由于我们是基于物理机也就是裸机(Bare Metal)部署,所以无论基于什么平台还是要考虑如何暴露 K8s 集群。

LoadBalancer

LoadBalancer 是 Kubernetes 官方推荐的暴露方式,很可惜它要部署在云厂商之上。我们公司全部是裸机环境部署,因此这个方式在一开始就被我们放弃了。

NodePort

NodePort 的端口范围一般是 30000 以上,每个端口只能对应一种服务,随着应用越来越多,端口可能不够用。除此之外,它最大的问题是如果你暴露某一个节点给外部访问,那么这个节点会成为单点。如果你要做高可用,这几个节点都暴露出去,前面一样也要加一个负载均衡,这样事情就复杂了。

Ingress

Ingress 可以解决 NodePort 端口复用的问题,它工作在 7 层上,可以复用 80 和 443 端口。使用 Ingress 的前提是必须要有 Ingress Controller 配合,而 Ingress Controller 同样会出现暴露端口并公开的问题。这时候如果你用 HostNetwork 或 HostPort 把端口暴露在当前的节点上,就存在单点问题;如果你是暴露多个节点的话,同样需要在前面再加一个 LB。

HostNetwork/HostPort

这是更暴力的方式,直接把 Pod 的端口绑定到宿主机的端口上。这时候端口冲突会是一个很大的问题,同时单点问题依旧存在。

5 发现 Porter

我们当时没有想出如何更优雅的解决这个问题,甚至都决定是不是还要像以前一样,在前面加一套 HAProxy with keepalived 做高可用。

后来我在浏览 KubeSphere 的文档时,在安装负载均衡器插件页面底部看到了一行不起眼的文字:

Porter 是一款适用于物理机部署 Kubernetes 的负载均衡器,该负载均衡器使用物理交换机实现,利用 BGP 和 ECMP 从而达到性能最优和高可用性,Porter 是一个提供用户在物理环境暴露服务和在云上暴露服务一致性体验的插件。

看到了物理机部署的字样后,我们发现这正是我们需要的东西。

Porter 的所有代码和文档已在 GitHub 开源 ,欢迎大家关注(Star)和使用。

点击查看 Porter 项目

6 使用 Porter 的前置条件

我们对 Porter 研究了很久,中间也踩了较多的坑,总结下来要用这个东西必须满足以下条件:

  • 首先你的路由器,也可以是三层交换机需要支持 BGP 协议。现在大多数路由设备都会支持这个协议,所以这个条件一般都能满足;
  • 其次集群节点上不能有和路由器建立 BGP 通信的服务。举例来说,当使用 Calico 时,开启了 BGP 模式。它的 BGP 模式有一种方式是让所有代理同时连到一个路由器,如果 Calico 和 Porter 要连的路由器是同一个的话,需要注意这个方案是有问题的。而 KubeSphere 默认安装的 Calico 是 IPIP 模式的,所以我们没有遇到冲突问题
  • 最后一定要有网络运维人员支持,配合你完成路由器配置以及了解整个网络拓扑结构。了解网络拓扑结构是非常重要的,否则会遇到很多问题。

7 物理部署架构图

Porter 官方介绍比较简单,有三张图片。这是第一张。这个网络结构应该是云环境的网络拓扑结构。在公司测试环境或者普通小机房不一定有这么复杂的网络结构。

我们来看下它是如何工作的,首先当你访问云上的 1.1.1.1 地址,请求转到 Border 路由器,Border 路由器再转到 Spine 交换机,Spine 交换机再转到 leaf 交换机,最后落到 K8s 的集群节点上。

Porter 的主要作用就是动态告诉这些路由器,整个路由应该怎么走。

我们再来看一个简单的例子。

假设你要做测试,你的办公室网络或测试网络可以组成这样一个简单的结构。如上图所示,一个三层核心交换机,所有网络都会连到它。同时整个网络还包括 K8s 集群的服务器。

以一个网段 10.0.0.0/16 为例,我们把这个网段可以定义为 K8s 集群的出口 IP,即ExternalIP(EIP),这些 IP 是不存在的。我们给每一个服务分配一个 EIP,所有到这些 IP 的请求最终会落到集群里的节点上。

要实现这个效果,一般比较笨的做法就是手动配置一个个的静态路由。这样的方式不太灵活,你要网工一直协助你操作路由器,维护成本是相当高的,肯定不适合生产环境。

Porter 的做法是只要你告诉它你要配置这样一个网段,由它的 Porter-Manager 与交换机建立 BGP 连接,并对所有 Load Balancer 类型的 Service 自动分配 EIP。它会把对应的路由规则直接写到交换机上,无需人工干预,这就是动态路由。

8 什么是 BGP

BGP 是边界网关协议(Border Gateway Protocol),是一种动态路由协议,使用 TCP 协议进行通信。BGP 在不同的自治系统(AS)之间交换路由信息。

9 什么是 AS

这里有一个新名词——自治系统(AS)

自治系统是什么?是一个(或多个)实体管辖下的所有 IP 网络和路由器的全体,每个自治系统都被分配一个唯一的自治系统编码(ASN)。你可以简单的理解为 AS 是一个公司,而 ASN 就是这个公司的唯一标识,像中国电信、中国联通、中国移动都有一个 ASN,如果他们之间要进行某些 IP 的路由交换,就是通过 BGP 来实现。

这里又提到一个新的名词 ASN,那这个 ASN 和我们的 Porter 又有什么关系呢?我们先来看下 ASN 的取值范围。

10 ASN 表

ASN,它最早的版本是 16 位的,现在可以支持 32 位,如果你的路由器比较老,可能 32 位不支持,所以我们一般还是使用 16 位的 ASN。红色部分的范围是 64512-65534,表示 ASN 的私有号段。大家可以理解为 IP 地址有公网和私网,ASN 也有公有和私有的概念。内部使用 ASN 只要用私有号段就可以了。

11 配置路由器和 Porter

到这里我们的基础知识基本补全了,可以开始配置路由器和 Porter 了。

我们设置这个 Porter 只需要用到两个 ASN,一个是设在路由器上(65001),另一个设在 Porter 上(65002)。他们互相之间要知道对方的 IP、端口和对方的 ASN。当路由器和 Porter 配置好并启动后,他们两个设备就建立了 BGP 连接。

12 Porter 插件逻辑

我们再来看下 Porter 架构的第二张图,现在来看就比较清晰了。

我们给路由器配了 ASN 65001,给 Porter-Manager 分配了ASN 65002。

Porter 内部会过滤所有 Load-Balancer 类型的 Service,当符合以下规则时,如果你指定了 IP 的话,它会分配给你指定的 IP;如果没有指定,就在指定网段范围里随机分配一个 IP。

annotations:
lb.kubesphere.io/v1alpha1: Porter
eIP.Porter.kubesphere.io/v1alpha1: <你要指定的IP>

插件列表

  • Porter-Manager
  • Porter-Agent

前面主要解释 Porter-Manager 的工作原理。Porter-Manager 是使用 Deployment 部署到 Master 节点上的,但默认只部署 1 个副本,它负责同步 BGP 路由到物理交换机。还有一个组件,Porter-Agent,它以 DaemonSet 的形式在所有节点都部署一个副本,功能是维护引流规则。

插件部署架构图

这是 Porter 第三张图。这里的 Agent 即 Porter-Agent,它是维护引流规则的,那具体是什么意思呢?

Porter-Agent 会根据 Service Endpoints 的变化动态调整路由,确保 EIP下一跳的 Node 节点一定有目标 Pod 存在。当你为 Service 开启 External Traffic Policy=Local 时,流量可直接转到节点本地 Pod,不会再增加一次跳转。

如果熟悉 External Traffic Policy=Local 这个设置的意义,你会知道这个东西有利有弊。好处是减少网络跳转,还可以拿到 SourceIP;缺点是它可能会导致负载不均衡。实际的情况还是需要进行调试和验证。

13 如何在 KubeSphere 上使用 Porter

虽然 KubeSphere 没有内置支持 Porter,但是我们在 KubeSphere UI 上进行简单的设置就可以使用 Porter 了。

支持 Ingress 访问

首先要在 KS 的项目(也就是 K8s 命名空间)的高级设置中启用网关。



我们在 Test 命名空间中开启了网关,并且设置了两个关键的 Annotation。

lb.kubesphere.io/v1alpha1: Porter
eIP.Porter.kubesphere.io/v1alpha1: 10.0.0.1

当网关的 ExternalIP 显示了我们设置的 10.0.0.1 IP 地址后,就表示当前命名空间的 Ingress 出口已经建立,接下来我们只要在 KS 的路由设置中添加 Ingress 。

加好路由后,只要把 www.benlai.com 域名指向到 10.0.0.1 后就可以访问了。

支持 TCP 访问

我们可能还有一些应用不是基于 HTTP/HTTPS 访问的,比如想暴露一个 MySQL 的 3306 端口给外部,这时候你就需要直接对 Service 进行设置。

我们选择了 10.0.0.2 这个 EIP 作为暴露 IP,以下是这个 Service 的 yaml :

kind: Service
apiVersion: v1
metadata:
    name: MySQL-zmit0e
    namespace: test
    labels:
        app: MySQL-zmit0e
    annotations:
        eIP.Porter.kubesphere.io/v1alpha1: 10.0.0.2
        lb.kubesphere.io/v1alpha1: Porter
spec: 
    ports:       
        - name: MySQL
            protocol: TCP
            port: 3306
            targetPort: 3306
    selector:
        app: MySQL-zmit0e
    type: LoadBalancer

当在 Service 列表里看到外网访问这列出现了 10.0.0.2 这个 IP 后,就表示该 Service 的 EIP 已经暴露给外部,这时候你就可以使用 MySQL 客户端对 10.0.0.2 进行连接了。

14 高可用架构

说到这里,你可能会有许多疑问,比如:

  • 单个路由器挂了怎么办?
  • 单个 Porter-Manager 挂了怎么办?
  • Porter-Manager 和路由器网络断了怎么办?
  • EIP 下一跳地址所在的节点挂了怎么办?
  • 某个 EIP 流量突然飙升,一个节点扛不住怎么办?

一般路由器或交换机都会准备两台做 VSU (Virtual Switching Unit) 实现高可用,这个是网络运维擅长的,这里不细讲了,可以参考 Porter 的第一张架构图里网络拓扑结构。我们重点讲下后面四点要怎么解决。

检查 BGP 路由表

首先我们要查下路由器上的 BGP 的路由表。如果 Porter 装好后一切正常,你在路由器上会看到这样一个 BGP 列表。其中星号代表这条 BGP 路由可用,大于号代表路由器现在正在使用这条路由规则。注意这是 BGP 路由,不是路由器的当前路由,这是有区别的。这个列表表示你把路由写到了 BGP 路由表里,每一个 EIP 只写了一条路由规则。

若要做到高可用,这里每个 EIP 对应的路由必须有两条以上。这样设置后,当 192.168.0.201 挂了以后,路由器会再从 BGP 路由表里选一条路由规则进行跳转。否则只有一条的话,这时候网络就断掉了,我们做过这样的测试。因此一定要确保 BGP 路由表是一个 EIP 对多个节点。

如果它不是这样的,你要找一下原因,是不是你的路由器没有配置好,或者你的 Porter 配置不对,或者有其他什么问题存在。

检查 BGP 邻居状态

接下来我们查看 BGP 的邻居状态。所谓的邻居状态意思是 Porter-Manager 在路由器上的连接状态。

默认安装 Porter,它只是在一个 Master 上部署 Porter-Manager。在邻居列表里能看到该 Porter-Manager,状态是 Established。注意检查其状态一定得是 Established。当状态为断开后,路由器会删除所有 Porter 提交的路由规则,也就是说当你的 Porter-Manager 挂了,你整个集群对外的网络也就挂了,是全部挂了。

我们应该怎么办?

我们要确保我们的路由器和 Porter-Manager 是多对多部署的。当你在路由表上看到你的 BGP 是上面图片这样的。无论是两个还是三个以上,它们的状态应该全部是 Established,并且列表中的收发数据量是会增长的,你就可以放心。但是你还是要时刻监控这张列表,预防全部断开连接的情况。

检查路由表

最后你要查看路由器真正的路由表,路由表大致是上图这样的。B 是 BGP 的缩写,代表当前这个路由是从 BGP 那边学习过来的。其中包含我们设置的 EIP 以及节点对应的 IP 地址。当你的路由表是这样的话,你需要担心流量突然增大时,你的节点撑不住怎么办?

我们还要做什么?

你要确保把路由器的等价路由(ECMP)开启,什么是等价路由?你告诉路由器这个 IP 有多条通路,让它自己做负载均衡,这才是路由器真正的负载均衡。

在路由器上要设置 MultIPath 或者 Additional Paths 才能开启等价路由,具体请参考路由器的操作手册。当你开启了等价路由后,你应该就能在路由表里能看到图中红色的部分。这个时候,你就可以不用担心某一天 10.0.0.1 突然流量很高的时候会压垮 192.168.0.201 这台机器了。

小结

我们归纳下实现高可用部署需要做的事情,还有要做好故障演练和压力测试。

  • 确保一个 EIP 有多条 BGP 路由;
  • 确保路由器和 Porter-Manager 是多对多部署;
  • 确保路由器开启等价路由(ECMP)。

15 Porter 的不足

  • 尚处于早期版本,稳定性需要经受考验;
  • 不支持 Service 的 spec.loadBalancerIP 字段,只能通过 annotations 中的eIP.Porter.kubesphere.io/v1alpha1 指定 IP 地址;
  • 文档较少。

一个比较新的东西肯定有不足的地方,我们使用 Porter 早期版本一直到现在,当中经历过踩坑的阶段。现在 Porter 处于 v0.1.1 的版本,稳定性是我们需要考虑的因素,这个需要在你的环境里测试和验证。其次这个项目需要更多的人使用和反馈,这样它才有进步,成为一个更稳定的版本。

16 未来的展望

  • 支持其他简单路由协议;
  • 更加方便的 VIP 管理;
  • BGP 的 Policy 支持;
  • 在 Kubesphere 集成,提供 UI。

这些是官方的计划,我们更期待最后一项的支持,这样我们的工作量又会小很多。

点击查看 KubeSphere 项目


相关资料

Porter 在 2019 年 6 月份上海的 KubeCon 上以 “Porter - An Open Source Load Balancer for Bare Metal Kubernetes” 的主题进行过分享,相关的视频资料大家可以在 Youtube 的 CNCF 官方视频下找到: https://www.youtube.com/watch?v=EjU1yAVxXYQ

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表