大家好,先简单自我介绍下,我叫厉辉,来自腾讯云。业余时间比较喜欢开源,现在是Apache APISIX PPMC。今天我来简单给大家介绍下 K8S Ingress 控制器的选型经验,今天我讲的这些内容需要大家对 K8S 有一定的了解,下面是我的分享。
阅读本文需要熟悉以下基本概念:
在 K8S 中,服务跟 Pod IP 主要供服务在集群内访问使用,对于集群外的应用是不可见的。怎么解决这个问题呢?为了让外部的应用能够访问 K8S 集群中的服务,通常解决办法是 NodePort 和 LoadBalancer。
这两种方案其实有各自的缺点,NodePort 的缺点是一个端口只能挂载一个 Service,而且为了更高的可用性,需要额外搭建一个负载均衡。LoadBalancer 的缺点则是每个服务都必须要有一个自己的 IP,不论是内网 IP 或者外网 IP。更多情况下,为了保证 LoadBalancer 的能力,一般需要依赖于云服务商。
在K8S的实践、部署中,为了解决像 Pod 迁移、Node Pod 端口、域名动态分配,或者是 Pod 后台地址动态更新这种问题,就产生了 ingress 解决方案。
Nginx ingress 的缺点
Ingress 是 K8S 中非常重要的外网流量入口,前面又拍云的总监也讲到了 K8S 默认的 Nginx ingress。这个 ingress 是 K8S 所推荐的默认的 ingress。为了跟后面的 Nginx 提供的商业版 ingress 作为区分,我就叫它叫 K8S ingress。K8S ingress,顾名思义基于 Nginx 的平台,Nginx 现在是世界上最流行的 Nginx HTTP Sever,相信在座各位都对 Nginx 比较熟悉,这是一个优点。第二个优点则是 Nginx ingress 接入 K8S 集群所需配置非常少,而且有很多文档来指引你如何使用这个 ingress。这对于大部分刚接触 K8S 的人或者创业公司来说,Nginx ingress 确实是一个非常好的选择。
但是当 Nginx ingress 在一些大环境上使用时,就会有非常多的问题。第一个,Nginx ingress它用了一些 OpenResty 的特性,但最终配置加载还是依赖于原有的 Nginx config reload。当路由配置非常大的时候,Nginx reload 会耗时非常久,可以达到几秒甚至十几秒,这种 reload 会很严重的影响业务,甚至造成业务中断,这是第一个问题。
第二个问题是 Nginx ingress 的插件开发非常困难,如果你觉得 Nginx ingress 本身插件够用,那还是可以用的。但如果想用一些定制化的插件,比如像阿里云的IM鉴权,或者是腾讯云的 KM 鉴权都需要进行额外的开发。Nginx ingress 开发插件非常痛苦,额外开发就非常麻烦,所以 Nginx ingress 的插件能力和可扩展性是比较差的。
Ingress 选型原则
既然发现了 Nginx ingress 有很多问题,那是不是考虑选择开源的更好用的 ingress,市场上说比 K8S ingress 好用的起码有十几家。如何从这么多 ingress 中选择适合自己的,这让人感到困扰。
Ingress 最终是基于 HTTP 网关的,市面上 HTTP 网关主要有这么几种。比如 Nginx、Golang 原生的以及新崛起的 Envoy 这些网关。但是每个开发人员所擅长的技术栈不同,例如我对 Nginx 比较熟悉,但有些人对 HAproxy 更加熟悉,或者有些人对新兴的 Envoy 这个网关更加熟悉。因为每个人熟悉的底层网关不一样,所以适合的 ingress 也会不一样。
那么问题来了,我们如何选择一个更加好用的 ingress 呢?或者缩小点范围,熟悉 Nginx 或 OpenResty 的开发人员,应该选择哪一个 ingress 呢?
下面来介绍一下我对 ingress 控制器选型的一些经验。
基本特点
图中的这些我觉得是基本功能,这些功能必须要有。如果连这些功能都没有,那完全可以直接pass。
基础软件
前面有提到,每个人擅长的技术平台不一样,所以选择自己更加熟悉的 HTTP 网关也显得至关重要。比如 Nginx、HAProxy、Envoy 或者是 Golang 原生网关。因为你熟悉它的原理,在使用中可以更快落地。
在生产环境上,高性能是一个很重要的点,但比之更重要的是高可用。这意味着你选择的网关,它的可用性、稳定性一定要非常强,只有这样,服务才能稳定。
功能需求
抛开上述两点,就是公司业务对网关的特殊需求。你选择一个开源产品,最好肯定是开箱能用的。比如你需要 GRPC 协议转换的能力,那当然希望选的网关直接支持这个功能。而肯定不希望去选择还需要开发的网关。这里简单列一下影响选择的点:
鉴权限流上,简单的鉴权是否足够,还是说需要更进阶的鉴权方式,或者要集成,或者很方便的能开发像阿里云、腾讯云的 IM 鉴权。前面我们有提到K8S ingress主要有这么些缺点,比如说 Nginx reload 的问题,插件扩展能力比较弱。其实它的后端节点调整权重的能力也不太好。
这里就要推荐一下 APISIX,它有非常强大的路由能力,插件能力也非常灵活。虽然它在功能上比 Kong 会少很多,但是 APISIX 很好的路由能力、灵活的插件能力,以及本身的高性能,能够弥补在 ingress 选型上的一些缺点。如果你们是基于 Nginx 或 Openresty 的开发人员,又对现在的 ingress 不满意,我推荐你们去使用 APISIX 作为 ingress。
如何将 APISIX 作为 ingress 呢?我们先要做出一个区分,ingress 是 K8S 名称的定义或者规则定义,ingress controller 是将 K8S 集群状态同步到网关的一个组件。但 APISIX 本身只是 API 网关,怎么把 APISIX 实现成 ingress controller 呢?我们先来简要了解一下如何实现 ingress。
实现 ingress,本质上就是两点。第一点,需要将 K8S 集群中的配置,或者 K8S 集群中的状态同步到 APISIX 集群。第二点,需要将 APISIX中 的一些概念,比如像服务、upstream 等概念定义为 K8S 中的 CRD。实现了第二部分的话,通过 K8S ingress 的配置,很快的去产生 APISIX,通过 APISIX ingress controller 就会产生 APISIX 相关的配置。我们当前为了快速的将 APISIX 落地为能够支持 K8S 的 ingress 。我们创建了一个开源项目,叫 ingress controller。
项目的架构大概是这样。左边是 K8S 的集群,这里可以导入一些 yaml 文件,对 K8S 进行配置上的变更。右边则是 APISIX 集群,以及它的控制面和数据面。在这里,APISIX Ingress 充当这两个 K8S 集群以及 APISIX 集群之间的连接者。它主要是监听 K8S 集群中节点的变化,去将集群中的状态同步到 APISIX 集群。另外,K8S 倡导所有组件都要高可用,所以 APISIX Ingress 设计之初,也考虑到它的高可用。我们通过双节点或多节点的模式,来实现 APISIX ingress controller 的高可用。
相对于市面上流行的 ingress 控制器,我们简单对比来看看 APISIX ingress 有什么优缺点。上图是外国开发人员针对 K8S ingress 选型做的一张表格。我在原来表格的基础上,结合自己的理解,将 APISIX ingress 的功能加入了进来。我们可以看到,最左边的是APISIX,后边就是 K8S ingress 和 Kong Ingress,后面的 Traefik,就是基于 Golang 的 ingress。HAproxy 是比较常见的,过去是比较流行的负载均衡器。Istio 和 Ambassador 是国外非常流行的两个ingress。
我们可以简单聊一下这些 ingress。首先说下 APISIX ingress,APISIX ingress 的优点前面也说到了,它有非常强大的路由能力,性能非常强,也有非常灵活的插件拓展能力。APISIX 刚开源没几个月,就已经有非常多的功能。但是它的缺点也非常明显,APISIX 有非常多的功能,但是缺少落地案例,没有文章去教大家如何将这些功能都给用起来。
第二个就是我前面吐槽了很多的 K8S ingress,也是那个 K8S 推荐的 Nginx Ingress。它的主要优点前面也说了,简单、易接入。但缺点就非常明显,Nginx reload根本就没有解决,插件是很多的,但插件扩展能力是非常弱的。
我们再说第三个,Nginx ingress主要优点是在于它对 TCP 和 UDP 协议的完全支持,但是其他的,比如像鉴权方式,或者流量调度,这个功能都是非常缺失的。
Kong 本身是一个 API 网关,他也算是开创了先河,将 API 网关引入到 K8S 中当 ingress。另外对于边缘网关,大家还是有很多需求的,比如说像鉴权、限流、灰度部署等能力。Kong 在这些方面做的非常好。另外 Kong ingress 还有一个非常大的优点,他提供了一些 API、服务的定义,去抽象成 K8S 的 CRD,所以可以很方便地通过 K8S ingress 配置,去同步到 Kong 的集群。虽然 Kong 有很多优点,但 Kong 也有一个非常大的缺点,那就是部署特别困难,另外他的高可用,与 APISIX 相比也是相形见绌。
Traefik 是基于 Golang 的 ingress,它本身是一个微服务网关,但是在 ingress 的场景应用比较多。他的主要平台是基于 Golang,自身支持的协议也非常多,总体来说是没有什么缺点。如果大家熟悉 Golang 的话,也推荐一用。
HAproxy,是一个久负盛名的负载均衡器。它主要优点是有非常强大的负载均衡能力,其他方面并不占优势。
Istio ingress 和 Ambassador ingress 都是基于最近非常流行的 envoy。说实话,我觉得这两个 ingress 没有什么缺点,可能唯一的缺点是他们基于 envoy 平台,大家对这个平台都不是很熟悉,上手门槛会比较高。
前面主要说了开源中的一些 ingress,现在再来说一下 ingress 在腾讯云的落地情况。前面提到的,像 K8S APISIX,或者是 ingress,他们都是开源的。K8S 跟 ingress,它们都是相互对应的。要聊腾讯云中的 ingress,自然要先去了解腾讯云中的 K8S 是什么。所以我先简要介绍一下腾讯云的 TKE,也就是腾讯云的 K8S 平台,然后再是腾讯云 ingress 的落地情况,它是集成了 CLB 来完成了 ingress 的功能。
上图是当前腾讯云的 TKE 平台的整体纵览,主要由用户接入层、核心功能,和整合产品三方面组成,整合产品将 Iaas 层和 PaaS 层进行了一些整合。
TKE 的全称是 Tencent Kubernetes Engine,是⼀个⾼度可扩展的⾼性能容器管理服务。最核心的是 TKE 解决了多租户的问题,K8S 本身是单租户的,怎么在腾讯云上变成多租户的场景呢?我们花了很长的时间去改造它。其次,在 K8S 节点内,解决了其他一些问题。我们采用了腾讯云的 VPC 的方案,解决了 Service 和 Pod 之间的通信问题。另外,内部网络集成了 vpc 的能力,对外网络集成 CLB 的负载均衡能力,硬盘存储上集成 CBS 的存储能力等等,最终实现了腾讯云 K8S 的公有云版。当前 TKE 在腾讯云上差不多有 200 万的状态吧。
CLB 是怎么样的?上图是腾讯云 CLB ingress 的整体架构图。因为我想从高性能、高可用的角度来讲我们的 ingress 集群,所以把 K8S 这块做了简化,只留了用户操作,API Server 以及控制器这些。
TKE 需要将 ingress 集成,只需将原有负载均衡的概念,去抽象成 K8S 中一些 CRD 的源语,然后就可以进行映射。比如创建 ingress 或者节点进行调度的时候,我们都可以通过调用 CLB 的接口去更新状态,完成整个 ingress 链路。
接下来就聊一下腾讯云 CLB 的高性能与高可用。因为后台服务最关注的也是这两点。
高性能
高性能网关主要说两部分,一是数据面,二是控制面。我们先说数据面,数据面这边的话,我们做的七层 CLB 主要是基于 Nginx。为了保证高性能,第一步就是要对 Nginx 进行优化。第二步优化是负载均衡,负载均衡最重要的就是 HTTPS 的能力,HTTPS 其实是非常消耗 CPU的。开源界里,HTTPS 的的优化空间非常大。举个例子,就比如开源 Nginx,我记不大清是八核还是四核,可以很轻松的达到10万 KBS。但是一旦用了 HTTPS 后,可能连 1 万 KBS 都达不到。所以 HTTPS 是有很大优化空间的。我们在做七层高性能时,花了很多时间去优化这块。怎么优化呢?百度搜一下 Nginx 常见的优化,结果里出现的,基本上都能优化,当然我们还做了另外一些细节上的优化。
第二部分是协议层上的优化,主要是对 HTTPS 协议本身的优化,这包含很多,包括加密协议、open ssl 库等,我们都做了一些优化。另外还有 HTTP2 协议的优化,HTTP2 是默认开启 TLS 加密的,所以也绕不过 HTTPS 协议的优化。
第二方面,我们做了很多控制面的的优化。前面已经提了很多次,只要用 Nginx,肯定避免不了 Nginx reload 的问题。只有几条路由时,可能没有问题。但是当有几千条、几十万条路由配置时,如果用 Nginx reload 至少要花十几秒,这对业务中断影响非常严重,完全不能接受。那该怎么办呢?我们作为一个云厂商,客户不仅仅在 upsteam这 块,在后台节点的变化也非常快,而且客户是共享集群,非常多的客户可能都在操作规则,例如操作 Nginx Server。所以我们又做了动态 Server 的优化。在完成 upstream 和动态 Server 这两个优化后,对于 99.9% 的规则,基本上都可以通过 Nginx 动态 Server 以及 Nginx 动态 upstream 来解决配置加载、变更,而不需要再去经历 Nginx reload,这是我们控制面的优化。
高可用
高可用也分两方面,一是控制集群,也就是控制面的高可用,二是数据面的高可用。我们先来说数据面的高可用。
数据面的高可用,主要是如上图的链路。四层网关与七层网关,七层网关与后端节点之间,其实他们都有专门的心跳探测,有熔断机制、超时能力等来保证高可用。比如发现某些节点有问题时,我会去剔除该节点。但也会去定时的拨测,一旦该节点恢复状态之后,会再将节点去加回来,这是第一方面,数据面的高可能主要通过心跳探测。
第二方面的话,也就是网关的跨可用区容灾。我们也做了一个 7 层网关与 4 层网关的跨可用区容灾比如当某一个机房的网关完全挂掉之后,我们依然可以提供一个高可用、高性能的服务。控制面的话这个主要是通过 master agent 集群化的模式来保证高可用。
说了 CLB ingress 的架构,看起来确实挺美好的,高可用,性能也非常好,那么它的缺点呢?其实它也是有一些缺点的。
第一,虽然前面说通过动态 upstream 和动态 Server 可以解决掉 99.9% 的配置变更问题,而不需要走 Nginx reload。但是本质上没有解决配置变更的一些问题,尤其是在一些突发或者后端节点比较多的情况下出现问题。因为过去的后端节点最多也就几十个,但是当 Docker 化时,后端节点很容易达到上千个甚至上万个。这时很容易触发动态 upstream 的域值,让本来应该走动态 upsteam 的,最终去走了 Nginx reload,这会产生非常严重的性能问题。
第二,CLB ingress 所有的逻辑、附加功能都是基于 Nginx,比如像 ACL 限流等都是通过 Nginx 模块来开发的。这样的话,首先开发门槛会非常高,其次开发效率也比较低。
我们对负载均衡的要求并不高。比如对负载均衡的主要要求,一是七层网关性能一定要好,二是 HTTPS 协议的支持能力一定要好,三是支持更多协议。但是对于 K8S ingress 的要求就不满足了,因为 K8S 有很多节点,我更希望有一个很好用的灰度能力。现在的 CLB,是满足不了定制化的灰度发布需求。所以,通过 TKE 集成了 CLB 负载均衡的能力,当作一个 ingress,只是到了能用的级别,但并没有完全的去贴合 K8S 平台的需要。
当前 CLB ingress 主要存在的问题就是这些。灰度能力比较弱,也很容易触发 Nginx reload,从而影响业务,除了这两点,还有就是隔离性非常差。CLB 的这种部署方式,依然还是很多客户共用一组 ingress。客户与客户之间,其实是会互相影响的。而 K8S 的设计理念是希望客户能够独占 ingress,不希望客户与客户之间的 ingress 会互相影响。我们想要解决上述的问题,恰巧遇见了 APISIX 这个项目。
APISIX 的优势是性能好,这里就不赘述了。另外 APISIX 插件能力灵活,可以支持在更多位置去插入插件。并且,APISIX 是从云原生角度去设计的,这意味着 APISIX 非常适合在容器中部署,不像过去的 CLB 在物理机上部署还好,但是在容器上部署,控制面架构就非常不适合。而 APISIX 的控制架构,我们可以非常轻松地选择是让客户去共用一组 ingress,还是每个客户有自己独占的 ingress。APISIX 在这三个方面都做的非常好,最终我们打算去落地 APISIX ingress 去替代 TKE 平台中的 ingress。
最后总结一下,虽然主要是聊 ingress 选型。前面其实就讲到了 ingress 的定位,如何去选择 ingress,选型要考虑哪些问题。后面将 APISIX ingress 与当前开源的一些 ingress 做了横向对比,让大家了解各个 ingress 的优劣势,方便后续选型时能够快速选择适合自己的 ingress。最后简要介绍了我们腾讯云的 CLB ingress,以及它当前存在的问题和下一步计划。
3 分钟带你深入了解 Cookie、Session、Token