apisix是什么?
apisix和kong非常相似,是一种基于OpenResty的网关。目前已经进入apache:
项目地址:https://github.com/apache/apisix
这里apisix的开发者写了这样一篇文章介绍为什么要有apisix:https://www.apiseven.com/blog/why-we-need-apache-apisix
这里简单摘要一下nginx和kong的痛点:
- 原生nginx不支持热更新配置,对于大型集群的网关,重新载入nginx配置会极为耗时,这个问题让他作为重度负载的网关非常致命,所以大多数情况下人们都会使用OpenResty的方案,在lua层面做路由。
- nginx原生不支持集群方案,只能在外部批量统一配置的情况保证集群一致。
- kong不支持mysql,而且可见的未来内似乎也没有支持的计划 https://github.com/Kong/kong/issues/1867 ┓( ´∀` )┏,一些社区支持的mysql-kong也都处于数年未更新的状态。对于国内mysql远流行于PG的环境不是很友好。
- Kong 的路由使用的是遍历查找,当网关内有超过上千个路由时,它的性能就会出现比较急剧的下降。
apisix的架构
先来认识下其基本架构
与kong将元数据保存在PG中不同,apisix选择将元数据保存在etcd。etcd能提供更强大的可用性,以及数据更新的及时性,能够使用etcd的watch机制毫秒级将控制面对配置的修改传播到数据面。
数据面架构如下:
也是基于OpenResty。按照文档的描述,apisix支持丰富的插件,lua插件,多语言插件运行器,wasm支持。
部署
我这里就直接helm部署到Kubernetes了。
1 | helm repo add apisix https://charts.apiseven.com |
可以调整下其中的配置把dashboard打开。
和konga非常类似。
启动好了大概这些容器:
1 | [root@node1 apisix]# kubectl get po -napisix |
一套etcd,apisix网关本体,和一个dashboard。
此外为了便于测试rewrite相关插件的效果,我这边还部署了一套httpbin:
镜像 : kennethreitz/httpbin
1 | [root@node1 apisix]# kubectl get po -napisix |
并建立httpbin对应的service。
实验
- 创建路由
我们基于域名匹配
为httpbin
插件配置里可以选择普通模式和编排模式,编排模式可视化的插件拼接还是比较酷的。这里我就先不配置插件了。
生成路由后,就可以通过NodePort
访问apisix的apisix-gateway这个service。
1 | [root@node1 apisix]# curl -iL -X GET "http://192.168.31.170:30599/get?foo1=bar1&foo2=bar2" -H "Host: abc.com" |
然后我们加些插件试试
添加一个重新请求的。
点开proxy-rewrite插件 配置上:
1 | { |
其中add是用于添加请求头,remove用于删除请求头,set用于覆盖请求头。
client -> 代理重写 -> upstream(httpbin) -> client
这里请求到httpbin,整个http请求将会被封装为json返回。我们看看代理重写的插件是否能加上我们的几个请求头。
再次请求:
1 | [root@node1 apisix]# curl -iL -X GET "http://192.168.31.170:30599/get?foo1=bar1&foo2=bar2" -H "Host: abc.com" |
再测试下限流插件:
点开插件配置为
1 | { |
反复请求会报出:
1 | [root@node1 apisix]# curl -iL -X GET "http://192.168.31.170:30599/get?foo1=bar1&foo2=bar2" -H "Host: abc.com" |
其他插件不一一测试了,文档非常详细。
https
在证书中配置了证书后,https访问对应域名会自动使用相关证书。我们用cfssl生成一个自签名证书证书试试。将其上传到证书里:
这里补充个知识点 SNI和SAN有什么区别:
SAN和SNI都是在SSL证书中用于多域名支持的技术,不过它们的作用不同:
● SAN(Subject Alternative Names):是在证书中设置的一个字段,用于指定该证书可以绑定哪些域名或主机名。在TLS握手的过程中,客户端会将请求的域名信息发送给服务器,在服务器返回证书的时候,如果证书中包含了请求的域名,就可以建立安全连接。SAN可以实现一个证书绑定多个域名的效果,比如 *.example.com 和 www.example.com 可以在同一个证书中绑定,也可以绑定不同的二级域名或顶级域名。
● SNI(Server Name Indication):是在TLS握手的过程中,客户端发送请求的域名给服务器的一个扩展字段。服务器根据这个字段,选择使用哪个SSL证书返回给客户端。SNI可以实现同一个IP地址上部署多个域名,使用不同的SSL证书加密通信的效果。在使用SNI前,客户端和服务器之间的通信只能使用IP地址和端口号,无法实现多域名共享一个IP地址的效果。
因此,SAN和SNI虽然都与SSL证书中多域名支持有关,但是作用不同。SAN是证书中的一个字段,用于指定可以绑定的多个域名;而SNI是TLS握手过程中的一个扩展字段,用于选择使用哪个SSL证书返回给客户端,实现同一个IP地址上部署多个域名的效果。
GRPC转码
还有个强大的功能是将外界的http请求转为grpc。
这里我用tonic中的example快速启动了一个helloworld server
https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/server.rs
里面的监听地址改为0.0.0.0:50051即可部署在k8s集群节点上或者pod内都可以。
对应的proto为:
1 | syntax = "proto3"; |
调用admin API配置proto协议:
1 | curl http://node1:31004/apisix/admin/protos/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' |
配置路由
1 | curl http://node1:31004/apisix/admin/routes/111 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' |
这里指明了我们需要的grpc转码插件。并指定了proto配置id。
最后我们验证下:
1 | curl -i http://node1:31001/ggrpc?name=world |
云原生
除了网关之外,apisix也推出了ServiceMesh,总的来说是想东西南北流量一把抓。但是总的来说,apisix最合适的定位还是ingress-controller。
此外,Gateway API 是 Kubernetes 中下一代的 Ingress 规范,致力于提供富有表现力,可扩展和面向角色的接口来发展 Kubernetes 的网络,各个 Ingress controller 项目都在积极推进对该规范的支持。
Gateway 对比 Ingress 有那些改进
- Gateway支持基于头的匹配,支持对请求头增删修改,这些功能之前只能将相关配置放在annotation中的方式,由ingress自行处理。 现在这些配置终于被k8s收编了。
- 跨命名空间引用,ingress-class虽然可以跨命名空间生效,但是ingress API却只能对当前命名空间生效,有时我们想代理另一个命名空间的资源,但是没有这个命名空间的权限就比较蛋疼了。Gateway目前是支持跨命名空间引用服务的。
还有其他一些优点这里就不一一列举了。总之后续ingress有可能被Gateway Api取代,目前nginx-ingress还没支持Gateway的计划,但是apisix目前已经支持了,这也是选择apisix一个有分量的理由。