网关是什么,为什么我们需要网关?
网关好比我们现实生活中的大门,我们要每天出门上班,下班回家都要通过大门进出。在网络世界中网关实际上起着控制流量进出的作用。我们平常使用电脑访问互联网,路由器承担了出去流量的网关的工作,在流量到达网关后,网关使用NAT技术完成了源地址转换。(可以理解为出门前换了一双鞋子)
当客户端流量到达服务端之后,也需要进入服务端的网关进行处理,这个网关通常也叫web反向代理,通常为了提高性能和安全考虑,不会直接把web中间件的端口直接暴露给用户
在服务端网关这层通常要完成认证、鉴权、流控等相关环节后进行路由转发给后端的web中间件处理,最终再将结果返回给客户端
目前我们的用的网关是啥?有什么优缺点?
市面上的网关产品或者解决方案主要分软件、硬件两种。硬件主要以F5为代表,软件则以nginx、openresty、kong等为代表。我们目前的所有项目均使用nginx来做服务端的网关
优点:
配置相对简单,参考文档和配置样例多
官方和第三方的模块丰富,可扩展性强
性能表现优异,系统开销低,并发吞吐能力强
缺点:
项目多,项目间相同的配置大量存在,配置文件可维护行差
所有的配置必须人工配置与校验,自动化能力弱
日志文件集中在本地,集群环境下分析工作量大
Kong是什么?
Kong是一个在Nginx运行的Lua应用程序,由lua-nginx-module实现。OpenResty不是Nginx的分支,而是一组扩展其功能的模块(整合了Lua模块后重新发布的nginx) 。Kong和OpenResty一起打包发行,其中已经包含了lua-nginx-module
可以简单理解为:
Kong > OpenResty > Nginx + lua-nginx-module
Kong 是在客户端和(微)服务间转发API通信的API网关,通过插件扩展功能。Kong 有两个主要组件:
Kong Server :基于nginx的服务,用来接收客户端请求,分api(默认8001)和http(默认8000)、https(默认8443)三个端口
Apache Cassandra或者postgresql数据库:用来持久化存储操作数据
Kong能解决什么问题?
Kong最诱人的一个特性是可以通过插件扩展已有功能,这些插件在 API 请求响应循环的生命周期中被执行。
插件使用 Lua 编写,Kong的内置插件功能有:
- 认证插件支持多种认证方式。如:basic auth、key auth、oauth2、hmac auth、jwt、ladp auth、session等
- 安全插件上支持针对消费者的API ACL策略控制、IP限制、机器人检测、acme自签免费证书等
- 流控插件上支持请求速率限制、请求大小限制、请求中断、代理缓存等
- 监控分析插件上支持prometheus、zipkin等
- 日志插件上支持接入TCP、UDP、HTTP协议的日志服务,同时支持syslog、statsd等日志服务
- 还有一些第三方的无服务插件,例如aws、azure等。
简而言之,kong在nginx、openresty的基础上整合了众多的功能,实现了API网关服务。
对我们而言,最直接的是可以通过api来配置nginx上的虚拟主机,通过使用官方提供的konga webui工具konga,使得配置管理可视化
Kong的几个重要概念
1、upstream
和nginx里面的upstream一致
api地址:http://192.168.1.16:8001/upstreams (192.168.1.16是kong服务的ip地址)
重要字段:
name:必须配置,和后面service关联的时候使用
algorithm:默认round-robin。目前支持三种:round-robin, consistent-hashing, least-connections
API配置示例:创建upstream
curl -i -X POST \
--url http://192.168.1.16:8001/upstreams/ \
--data 'name=fjwjw-dev-web' \
--data 'algorithm=round-robin'
curl -i -X POST \
--url http://192.168.1.16:8001/upstreams/ \
--data 'name=fjwjw-dev-static' \
--data 'algorithm=round-robin'
2、target
和前面的upstream相关联,配置后端web中间件的ip地址和端口,权重等
api地址:http://192.168.1.16:8001/upstreams/fjwjw-dev-web/targets (fjwjw是前面upstream的名称)
重要字段:
target: 后端web中间件的ip地址和端口,不配置端口默认为8000
weight:权重
API配置示例:创建target,关联前面创建好的upstream
curl -i -X POST \
--url http://192.168.1.16:8001/upstreams/fjwjw-dev-web/targets \
--data 'target=192.168.1.60:80' \
--data 'weight=100'
curl -i -X POST \
--url http://192.168.1.16:8001/upstreams/fjwjw-dev-web/targets \
--data 'target=192.168.1.61:80' \
--data 'weight=100'
curl -i -X POST \
--url http://192.168.1.16:8001/upstreams/fjwjw-dev-static/targets \
--data 'target=192.168.1.13:1457' \
--data 'weight=100'
3、service
和前面的upstream相关联,配置虚拟主机相关的信息
api地址:http://192.168.1.16:8001/services/
重要字段:
name:服务名称
host:和upstream相关联的字段
port:指定upstream端口
protocol:指定连接后端的协议
connect_timeout:客户端连接超时时长
read_timeout: 客户端读取超时时长
write_timeout: 客户端写入超时时长
ca_certificates:服务端ca证书相关关联
client_certificate: 客户端证书相关
retries:后端重试次数
API配置示例:创建service,关联upstream
curl -i -X POST \
--url http://192.168.1.16:8001/services/ \
--data 'name=fjwjw-dev-web' \
--data 'path="/web"' \
--data 'url=http://fjwjw-dev-web'
curl -i -X POST \
--url http://192.168.1.16:8001/services/ \
--data 'name=fjwjw-dev-static' \
--data 'path=/' \
--data 'url=http://fjwjw-dev-static'
4、route
api地址:http://192.168.1.16:8001/routes
重要字段:
name:路由规则的名称
paths:路径
service:和哪个service关联
methods: 支持的http方法(需要大写)
hosts: 具体访问的域名
API配置示例:创建route,和前面的service相关联
curl -i -X POST \
--url http://192.168.1.16:8001/services/fjwjw-dev-web/routes \
--data 'name=fjwjw-dev-web' \
--data 'hosts[]=fjszyws.dev.59iedu.com' \
--data 'paths=/web' \
--data 'preserve_host=true' \
--data 'strip_path=false'
curl -i -X POST \
--url http://192.168.1.16:8001/services/fjwjw-dev-static/routes \
--data 'name=fjwjw-dev-static' \
--data 'hosts[]=fjszyws.dev.59iedu.com' \
--data 'paths=/' \
--data 'preserve_host=true' \
--data 'strip_path=false'
5、consumer
Consumer是使用Service的用户,其核心原则是为其添加Plugin插件,从而自定义他的请求行为.
最简单的理解和配置consumer的方式是,将其于用户进行一一映射,即一个consumer代表一个用户(或应用)
api地址:http://192.168.1.16:8001/consumers
使用API网关需要哪些方面的调整和挑战
1、 动静分离完全拆分
目前我们项目的前后端的入口都是nginx,域名完全一致。
api网关实际上更适合处理动态部分的请求。虽然不拆分前后端请求域名也能满足现有需求,但从规范性以及后续静态资源CDN加速等方面考虑,建议前后端域名进行拆分。
另外,拆分之后api网关和K8S服务集成,可以使用K8S服务名与后端进行动态关联。
2、日志收集与分析
使用api网关之后,所有的项目日志集中化存储,运维分析上将带来挑战,需要一套完整的日志解决方案
3、核心插件适配
使用api网关之后,客户端认证、鉴权、流控等工作不需要再由应用程序完成,网关层可以承担这部分工作,在认证、鉴权、流控插件上需要适配我们的项目和应用