如何将流量在多个 Kubernetes 集群之间进行负载均衡,并做到自动的灾备切换一直是一个让人头疼的问题。我们之前调研了公有云,Karmada Ingress,自己也做了一些手动 DNS 的方案,但这些方案在成本,通用性,灵活度以及自动化程度上都有所欠缺。直到调研到了 k8gb 这个由南非银行 Absa Group 为了做金融级别的多活而启动的一个项目。k8gb 巧妙的利用了 DNS 的各种协议完成了一个通用且高度自动化的 GSLB 方案,看完后我就再也不想用其他的方案了。这篇博客会简单介绍一下其他几个方案各自存在的问题,以及 k8gb 究竟是如何巧妙的利用 DNS 来实现的 GSLB。
GSLB(Global Service Load Balancer)是相对于单集群负载均衡的一个概念,单集群负载均衡主要作为一个集群的入口将流量分发到集群内部,而 GSLB 通常作为再上一层多个集群的流量入口,进行流量负载均衡和故障处理。一方面 GSLB 可以设置一些地理亲和的规则达到流量就近转发提升整体的性能,另一方面当某个集群出现问题后可以自动将流量切换到正常集群,减少单个集群故障对用户的影响。
GSLB 并不是一个新出的概念,所以不少商业公司都在这方面有很成熟的产品,例如 F5 GSLB。这类产品通常有以下几个缺点:
公有云为了解决流量多地域分发会提供多集群负载均衡的产品,例如 AWS 的 Global Accelerator 和 GCP 的 External Application Load Balancer。GCP 上甚至还有一组自定义的 Multi Cluster Ingress 资源,可以很好的和 Kubernetes 里的 Ingress 进行对接。但是他们也有一下几个问题:
Karmada 是一个多集群的编排工具,也提供了自己的多集群流量调度方案 Karmada Multi Cluster Ingress。该方案通过在某个集群内部署一个由 Karmada 社区提供的 ingress-nginx 以及定义 MultiClusterIngress
来完成多集群流量调度,但这个方案有以下几个问题:
如果手动攒出来一个简单的基于 DNS 的方案其实也是可以的,大部分 DNS 厂商都提供了健康检查的功能,因此我们可以将多个集群的出口 IP 地址加入到 DNS 的解析记录里,同时配置健康检查来做故障切换。但是这个简单的方案在规模扩大后就会有一些明显的限制:
k8gb 的解决方案其实也是用 DNS,但是通过自己的一系列巧妙的设计,解决了上面提到的简单 DNS 方案的一系列缺陷。
简单 DNS 方案的问题本质是没有和 Kubernetes 进行很好的对接,Kubernetes 内的一些动态信息,例如新增的 Ingress,新增的域名,服务的健康状态没法很好的同步到上游 DNS 服务器,而上游 DNS 服务器简单的健康检查也没办法应付 Kubernetes 里这种复杂的变化。因此 k8gb 最核心的一个变化就是上游的 DNS 记录不再是通过 A 记录或者 AAAA 记录指向集群的一个出口地址,而是 forward 到集群内的一个自己配置的 CoreDNS 进行 DNS 解析,将真正复杂的 DNS 逻辑下沉到集群里来自己控制。这样上游 DNS 只需要做简单的代理,不再需要配置健康检查,也不再需要动态的调整多个地址映射。
调整后用户请求 DNS 的流程如下图所示:
这种方式管理员只需要在上游 DNS 注册几个域名后缀并代理到每个集群的 CoreDNS 就可以了,k8gb 本身也提供了自动化的能力,只要配好证书可以自动分析 Ingress 内使用的域名自动注册给上游 DNS,大幅简化了管理员的操作。
整个流程中还有一个特殊的点要注意,就是每个集群自己的 CoreDNS 不能只记录本集群 Ingress IP 的地址,还需要记录其他集群同一个 Ingress 的 Ingress IP 地址。因为如果只记录本集群的,当本集群对应服务的 Pod 都 Not Ready 时,CoreDNS 会返回 NXDomain 如果客户端收到了这个返回就会按照域名无法解析处理,此时另一个集群服务其实是可以正常提供服务的。因此 k8gb 还需要同步所有集群同一个域名 Ingress 对应的 Ingress IP 和它的健康状态。
众所周知多集群之间的数据同步也是一个世界难题,但是 k8gb 同样通过 DNS 巧妙的实现了数据的同步。
同步的流程图如下所示:
大致的思路是每个集群的 k8gb 会把自己的 CoreDNS 的 Ingress IP 同样注册到上游 CoreDNS,这样每个集群就可以直接访问另一个集群的 CoreDNS 了。然后每个集群内的 CoreDNS 再按照一个特殊的域名格式比如 localtargets-app.cloud.example.com
来保存本集群内 app.cloud.example.com
Ingress 的 Ingress IP 并维护其健康状态。这样每个集群就都可以通过这个特殊的域名来或者其他集群这个域名对应的 Ingress IP 然后加入到自己的返回结果里,实现了域名解析的多集群同步。
k8gb 作为一款开源的 GSLB 实现了和 Kubernetes 的无缝对接,能够很好的对跨集群的域名和流量进行自动化管理,并且对外部的依赖降到了只需要一个添加 DNS 记录的 API,真正实现了一套可以多云统一的 GSLB 方案。尽管目前这个项目还没有那么火热,但在我心里它已经是这个领域内的最佳方案了。