API 网关功能以及未来展望
我们平台项目中其实一直在考虑 API 网关的功能扩展,目前使用的 K8s Ingress 以及 Istio 提供的 Istio gateway,额外功能实在不多,仅仅能实现暴露接口的需求。我近期也认真调研了下市场中的 API 网关产品,针对这些产品,简单介绍下功能以及给出一些自己对于未来发展方向的考量,希望能抛砖引玉,愿读者分享自己对于 API 网关的展望。我提了一些方案,有兴趣的读者可以业余一起做做看。
极简功能
目前我们所使用的网关有两种,我在之前的博客中都有介绍 : Kubernetes Ingress[1],Istio Ingress Gateway[2]。用的功能不多,基本只有灰度和转发,鉴权,限流的功能完全没依靠它们实现。
Kubernetes Ingress
我们使用的是 K8s 社区基于 OpenResty 的实现,与 Service 来配合使用:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: arya-prod
spec:
rules:
- host: arya.example.com
http:
paths:
- path: /
backend:
serviceName: arya-svc
servicePort: 80
Istio Ingress Gateway
由于某些原因,不得不使用这种 Ingress,需要一起使用 Gateway 和 VirtualService,也需要 Service。
# 指定要接收流量的gateway
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: arya-gateway
namespace: xxx-group-2
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "arya-python3.istio.xxx.com"
# virtual-service用于说明gateway的流量如何处理
# 可以看到,这里是允许使用前缀路径来做转发的,这种方案可以不需要DestinationRule
# 完全用kubernetes的service来做
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: arya-virtual-service
namespace: xxx-group-2
spec:
hosts:
- "arya-python3.istio.xxx.com"
gateways:
- arya-gateway
http:
- match:
- uri:
prefix: /static
route:
- destination:
host: prod-arya-python3-static
- match:
- uri:
prefix: /
route:
- destination:
host: prod-arya-python3
现有的网关与插件功能
我个人认为网关不应该只有普通的转发功能,还包括鉴权,限流等功能,这些功能应该是网关的一部分,并且应该是可以插件化的。我不一定要求直接编辑 Nginx 配置,但是当我想增加扩展的时候,希望可以有这么一个选项。下面就按照我自己的调研内容。
Kong
Kong 文档[3]
之前看到 Kong 这个产品,它的底层使用了 OpenResty,但是实现了插件系统,可以说是 Kubernetes 社区 Ingress 的增强版。也支持 Python,Golang 的一类插件,我简单介绍下使用方式:
---
apiVersion: configuration.konghq.com/v1
plugin: openid-connect
kind: KongPlugin
metadata:
name: oidc-auth
config:
issuer: https://accounts.google.com/.well-known/openid-configuration
client_id:
- <client-id>
client_secret:
- <client-secret>
redirect_uri:
- http://192.0.2.8.xip.io
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: productpage
namespace: bookinfo
annotations:
konghq.com/plugins: oidc-auth # 多个插件可以使用数组
spec:
ingressClassName: kong
rules:
- http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: productpage
port:
number: 9080
我比较喜欢它的交互逻辑,当你有多个域名时,每个域名可以设置自己启用的插件及其配置。它已经是成熟的商业化产品,所以可用性方面还是很强的,很可惜目前还不支持 Wasm。
Istio
Istio 文档[4]
Istio 中使用的 Envoy,已经支持了 wasm 插件。
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: openid-connect
namespace: istio-ingress
spec:
selector:
labels:
istio: ingressgateway
url: oci://private-registry:5000/openid-connect/openid:latest
imagePullPolicy: IfNotPresent
imagePullSecret: private-registry-pull-secret
phase: AUTHN
pluginConfig:
openid_server: authn
openid_realm: ingress
不过即使是最新版本的 Istio 对插件的支持都不怎么样,没法单独针对一个 virtual service 增加插件。这里的 selector 是针对 ingress gateway 的,也就是说,所有网关上的 virtual service 都会被影响。而且多个插件的行为是使用 proiority 来控制的,用户的交互会十分困难,可用性太差了。
几种可能方向与技术预研
针对几种可能的方案,我做了一些简单的探索和研究。这里我贴出的方案,我都调研了其可能的实现策略,也都有把握将其落地。读者有什么想法也可以一起与我交流。
针对 Kong 可能的优化
单从交互逻辑以及可用性方面,我觉得没什么可优化的,唯一让我觉得难受的地方就是无法使用 wasm 类型的插件。
有几种可能的方案:
-
类似 kong 的 Golang,Python 插件,远程 rpc 调用来实现 -
Lua 实现 vm,直接运行 Wasm 代码 -
将 Wasm 嵌入到 OpenResty,这是一种支持 Wasm 的思路 : https://github.com/api7/wasm-nginx-module
我臆测这是 Kong 团队会考量后两种。对于第一种,Python,Golang 类插件所带来的维护成本,用户体验也并不友好 . 后面两种,它对于 Wasm 是原生的支持。不管是后期维护,还是性能方面,感觉都会好很多。
针对 Istio 可能的优化
交互逻辑上
由于 Envoy 原生支持 Wasm,所以这块我比较看好。但是如果想要作为网关,交互逻辑上可能需要改造下,绑定到 VirtualService 或是 Gateway 上是比较合理的。
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: arya-virtual-service
namespace: xxx-group-2
annotations:
istio.io/plugins: oidc-auth # 多个插件可以使用数组
spec:
hosts:
- "arya-python3.istio.xxx.com"
gateways:
- arya-gateway
http:
- match:
- uri:
prefix: /static
route:
- destination:
host: prod-arya-python3-static
- match:
- uri:
prefix: /
route:
- destination:
host: prod-arya-python3
Envoy Lua 插件支持
为什么要支持 Lua 插件 我看中的是 Kong 现有的插件生态。几乎所有的 Lua 插件都是经过了企业级的认证,如果能在 Istio+Envoy 中直接使用,相信很多用户会愿意使用 Envoy 作为网关。
Lua 插件的支持其实有两种可行方案的:
-
Lua 直接编译到 wasm,据我搜集到的资料来看,没有现成的编译器,需要自己手写 -
近期看到,网易数帆针对 Envoy 添加了 Lua 支持,也就可以考虑模拟 Kong 的 PDK 来使用其插件
https://xie.infoq.cn/article/1cb74a7512460b7d4dbc9f42c
博客中内容,我觉得性能检测那边有点问题,无论何种语言编写的 wasm 插件,它已经变成了类似汇编的字节码,性能差距不应该很大,博客中以 C++来做最有的效果衡量让我感觉不是很有说服力。但是博客切实的将 Lua 嵌入到了 Envoy,性能可以慢慢优化,做出来成品还是很重要的。
扩展型 sidecar
我的博客中有许多讨论 PaaS 平台建设的文章,我本人也在维护一个 PaaS 平台,所以我也从 PaaS 的角度给出一些方案。
上面两种改造方案是需要我们去改进控制器以及底层代码来实现的。对于一个 PaaS 平台来说,我们不会深入到这样的底层系统,对它改造太困难了。如果我们想要拥有完善的网关功能,同时考虑用户的交互逻辑,比较好的策略是用户在代码中指定一些特殊配置,无论是使用 nginx
,lua
或是 wasm
配置,我们都对其支持。使用类似 Istio 中 sidecar 的形式,该 sidecar 仅作为 API 网关,并不截取所有流量。这样考虑有两点:
-
性能问题,sidecar 与 pod 扩缩容绑定,理论上讲与 Istio 的性能一致 -
扩展性很重要,如果我们只是简单的使用 Istio,用户的需求很可能无法尽快满足,这一点上的响应速度会很慢
个人看法与 PaaS 平台方向
技术本身没有什么好坏,只有适合不适合。
对于 PaaS 平台,可扩展性和简易的交互逻辑是很重要的,我们有成百上千个小项目,就会有各种各样的需求。我们不能寄希望于完全使用 Istio 的描述文件来扩展平台功能,而是应该总结需求的底层逻辑,在现有方案无法支持的情况下提出备用方案给用户。我们应该会采用扩展型 sidecar 的形式,允许用户写一部分配置并托管到 Git 仓库。
我个人喜好,当我个人用 K8s 维护几个小的项目时,我自己倒是很希望一些功能的插件化,因此我个人比较喜欢类似 Kong 插件的形式进行交互,但是我又想要有 Wasm 的支持。所以我会偏好 Istio+Envoy 的形式,如果能够改进 Wasm 的插件形式并且使用有 Lua 功能支持的 Envoy,我可能会把自己的项目全部切到 Istio 上。业余时间应该我会考虑改进 Istio 的控制器。
总结
文章篇幅比较多,你可以把它理解为一份调查报告。基本都是现有的业务逻辑分析,还有个人拙见。大佬们觉得对于哪种方向有看法或是兴趣,都很欢迎与我讨论和沟通。
引用链接
Kubernetes Ingress: https://corvo.myseu.cn/2019/11/05/2019-11-05-Kubernetes中Ingress的使用/
[2]Istio Ingress Gateway: https://corvo.myseu.cn/2021/06/22/2021-06-22-Istio-%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8(Gateway)/
[3]Kong 文档: https://docs.konghq.com/kubernetes-ingress-controller/2.3.x/guides/configure-acl-plugin/
[4]Istio 文档: https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/
你可能还喜欢
RethinkDB:为什么我们失败了云原生是一种信仰 🤘
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!
点击 "阅读原文" 获取更好的阅读体验!