Kong API 网关分享
一、业务背景
1.1、从“巨石应用”到“微应用”
这里需要一个单体应用,随着版本迭代、业务增多,发展到巨石应用。而我通过对巨石应用改造,将项目松散解耦,过渡到微应用。顺便提一下微应用的好处,巨石应用的弊端。
巨石应用
- 项目体积庞大
- 编译部署时间过长
- 开发效率低下
- 项目耦合严重,牵一发而动全身
微应用的架构设计
微应用的架构设计,本质上是应用拆分和组合。对比Nginx方案和新方案的优劣,引出微服务网关的愿景。
微服务的核心是应用拆分与组合,一般是按业务拆分应用。微应用系统架构如下:
1.2、微服务网关的愿景
细分微服务愿景,展开将对微服务网关的终极诉求。
应用的拆分与组合,一般可以通过Nginx来实现,但Nginx方案不够完美,有以下问题:
- 前端不能享受SPA(单页面应用)的体验
- 应用隔离很完美,应用之间数据共享比较麻烦。比如共用侧导航、消息通信
- 类似限流,下线服务,禁IP等操作需要SRE协助修改静态配置文件,不够灵活
- 鉴权代码要写在业务代码里,不好复用,业务代码不够纯粹,存在代码冗余。
微前端采用icestark、qiankun等框架做应用组合和分发,这里不再赘述。
微服务可以采用API网关来统一做服务的入口管理,统一分发服务,进行限流、鉴权、监控、日志、缓存等操作。客户端请求,必须通过API网关,隐藏真实的后端服务地址。确保后端的安全性。
网关应具备以下功能
- 性能:API高可用,负载均衡,容错机制。
- 安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
- 日志:日志记录(spainid,traceid)一旦涉及分布式,全链路跟踪必不可少。
- 缓存:数据缓存。
- 监控:记录请求响应数据,api耗时分析,性能监控。
- 限流:流量控制,错峰流控,可以定义多种限流规则。
- 灰度:线上灰度部署,可以减小风险。
- 路由:动态路由规则。
除此之外,还希望有以下功能:
- 适合RD。通过RESTFul API就可以配置Nginx转发
- 高扩展性。可以把路由,安全,限流,缓存,日志,监控,重试,熔断等都放到 API 网关来做,然后服务层就完全脱离这些东西,纯粹的做业务,也能够很好的保证业务代码的干净,不用关心安全,压力等方面的问题。
- 高性能。有一定容错机制、负载均衡能力。
二、技术选型
讲解一下公司内部的系统,再分析kong网关的系统架构,再浅析一下spring cloud gateway、apisix等网关系统
2.1、公司内的网关系统
请求进入到L7(Nginx项目),反向代理。自己做upstreams负载均衡,或者反向代理到elb域名上做负载均衡。
使用 nginx 进行流量限制,问题在于 nginx 的配置规则是以静态文件的形式进行管理的,无法通过 api 或者后台灵活的修改流量的封禁、降级和调度策略,同时配置生效需要 reload;
2.2、kong网关
基于Nginx + Openresty Api 网关
kong的优势
- 面向RD,用RESTful风格API配置Nginx。
- 配合 kanga 可实现可视化操作,多种插件可选,实现服务监控限流熔断等等功能
- 可开发插件,自由扩展功能。目前支持midun-proxy(米盾鉴权)、business-auth(通用后台业务鉴权)、replace-uri(uri部分替换)。后面可考虑加入日志、飞书报警等
- 开源并且基于 nginx 性能卓越
- 跨语言,任何语言的写的后端服务都可以使用
名词解释:
- Route 路由通过 host, path, header 等维度匹配客户端 url, 如设置规则 host:www.haodf.com path:/test1 匹配 url: www.haodf.com/test1。
- Service 服务是对后端服务的抽象。
- Upstream 负载均衡对象,用于设置主动或者被动心跳检测机制,负载均衡规则(轮询或者 hash)等。
- Target 配置的是后端服务的实际 ip 和端口。
- Plugins 插件,附加功能支持身份验证,限流,拦截等,可作用层级 Route,Service,全局。
kong的架构
请求流程简要说明:
当客户端发起请求时流量会先统一打到 Kong,Kong 通过 Route(路由)对象来匹配规则,再通过 Route 去找当前请求对应的 Service 服务,最后通过 Upstream 负载均衡至后端机器。附加功能(身份验证,黑白名单等)通过 Plugins 插件的形式,附加到 Route 或者 Service 上动态加载,作用于 nginx 请求的各个阶段。
Kong 就是在 openresty 各个阶段加入了 Kong 的 lua 代码来实现一些 Kong 的功能,以下是 Kong 的 nginx 简要配置。
init_by_lua_block {
kong = require 'kong'
kong.init() // 完成 Kong 的初始化,路由创建,插件预加载等
}
init_worker_by_lua_block {
kong.init_worker() // 初始化 Kong 事件, worker 之间的事件,由 worker_events 来处理, cluster 节点之间的事件,由 cluster_events 来处理,缓存机制
}
upstream kong_upstream {
server 0.0.0.1;
balancer_by_lua_block {
kong.balancer() //负载均衡
}
keepalive 60;
}
# ... 省略若干
location / {
rewrite_by_lua_block {
kong.rewrite() //插件生效策略的筛选,并执行对应的操作,只能处理全局插件(kong插件级别,全局(作用于所有请求),route(作用于当前路由),service(作用于匹配到当前service的所有请求)),路由匹配未开始。
}
access_by_lua_block {
kong.access() //1.完成路由匹配,2.确认加载的插件(并加入缓存) 3.进入balancer阶段
}
header_filter_by_lua_block {
kong.header_filter() //遍历在缓存中的插件列表,并执行
}
body_filter_by_lua_block {
kong.body_filter() //遍历在缓存中的插件列表,并执行
}
log_by_lua_block {
kong.log() //遍历在缓存中的插件列表,并执行
}
}
2.3、网关对比
- Apisix 不支持mysql
- Spring cloud GateWay 与其它语言结合比较麻烦
- NodeJS 应用较少
三、项目实战
讲下如何部署kong和konga,如何开发kong插件
3.1、基于MICE部署kong + konga,数据库用mysql
- 首先创建数据库,数据库名kong和konga,分别做kong和konga的数据存储。
- 登录mice个人账号,参考:cloud.mioffice.cn/product/doc…
- 初始化kong数据库(*为占位符)
docker run --rm -e "KONG_DATABASE=mysql" -e "KONG_MYSQL_HOST= *.*.*.*" -e "KONG_MYSQL_USER=root" -e "KONG_MYSQL_PASSWORD= ******" cr.d.xiaomi.net/open-tsm/kong-support-mysql:1.0.0 kong migrations bootstrap
- 启动kong
docker run -d --name kong-local -e "KONG_DATABASE=mysql" -e "KONG_MYSQL_HOST=*.*.*.*" -e "KONG_MYSQL_USER=root" -e "KONG_MYSQL_PASSWORD=******" -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" -e "KONG_PROXY_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" -p 8000:8000 -p 8443:8443 -p 8001:8001 -p 8444:8444 cr.d.xiaomi.net/open-tsm/kong-support-mysql:1.0.0
- 访问http://localhost:8001,查看kong配置项
- 通过http://localhost:8001管理API,或者搭建konga可视化界面管理API
- 访问http://localhost:8000/{route},验证代理是否成功
- 初始化konga数据库
docker run --rm konga:1.0.1 -c prepare -a mysql -u mysql://root@mysql_host/konga
- 运行konga
docker run -p 1337:1337 -e "DB_ADAPTER=mysql" -e "NODE_ENV=production" --name konga konga:1.0.1
- 访问http://localhost:1337,注册konga管理员账号,登录进去
- 添加kong网关链接,然后配置services、routes、upstreams、插件等。
3.2、开发kong插件
Nginx Lua执行步骤
kong插件文件结构
- 文件名、文件目录结构是固定,plugin名字可以调整
- handler.lua 一个需要实现的接口,其中每个方法会在请求/连接的生命周期中运行
- schema.lua 保存插件的配置项,以便用户只能输入有效的配置值
- kong-plugin-*-version.rockspec,用于luarocks编译打包,修改相应的插件名字即可。
- mv.sh一个shell脚本,不是必须的。用于开发调试插件时,执行lua文件拷贝,kong容器重启等命令
kong插件本地开发方式
采用挂载文件夹的方式 -v
docker run -d --name kong-local -v /Users/yaodi/Workspace/Docker/kong/custom-plugins:/usr/yaodi -e "KONG_DATABASE=mysql" -e "KONG_MYSQL_HOST=*.*.*.*" -e "KONG_MYSQL_USER=root" -e "KONG_MYSQL_PASSWORD=*******" -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" -e "KONG_PROXY_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" -p 8000:8000 -p 8443:8443 -p 8001:8001 -p 8444:8444 cr.d.xiaomi.net/yaodi1/kong-support-mysql:1.0.1
然后,/etc/kong/kong.conf里这样改
lua_package_path = ./?.lua;./?/init.lua;/usr/yaodi/?.lua;
再写一个shell脚本,进行文件copy,并且重启容器。用postman验证。
cp -r ./kong ../custom-plugins/
docker restart kong-local
提示没有lua.resty.rsa,安装
luarocks install lua-resty-rsa
- Kong本身依赖Nginx、OpenResty、Lua,依赖比较多,由于kong本身不需要更改,我们直接用docker镜像部署,而需要扩展的功能则通过插件来引入,kong镜像一般不会改。
- 那么本地开发插件方便吗?首先,在mice上把kong镜像拉下来,docker run把镜像跑起来,-v 设置kong镜像文件夹/var/plugins到宿主机文件夹的映射。修改/etc/kong/kong.conf配置,lua包文件地址增加一个kong镜像文件夹/var/plugins。这样kong镜像就会自动加载宿主机文件夹里的lua插件了。修改插件,docaker restart 重启镜像,添加插件到指定的route、service或者global上,curl 验证插件。docker app上查看镜像日志。
四、遇到的问题
4.1 kong 不支持mysql
4.2 konga
微服务架构中加入API Gateway(API网关)作用
一般也会把路由,安全,限流,缓存,日志,监控,重试,熔断等都放到 API 网关来做,然后服务层就完全脱离这些东西,纯粹的做业务,也能够很好的保证业务代码的干净,不用关心安全,压力等方面的问题。
客户端请求,必须通过API网关,隐藏真实的服务端地址。反向代理,如代理商
架构层面
性能 与 业务可扩展性
Docker是一个开源的应用容器引擎,
专注于开发,不用关心环境。更好的应用的隔离
Kong项目启动之后会去监听端口,并未客户端提供服务,开发者可以添加API接口客户端可以访问API接口提供调用
集群网关
8000:会监听来自客户端的传入HTTP流量,并剑气转发给上游服务
8443: 监听客户端传入的HTTPS流浪
8001:端口 admin api监听端口 开发者端口
我们开发一个网关工程,肯定不希望网关工程对通用后台工程带来负向影响的,根据网上翻越的资料kong网关对网络请求的几乎是无影响的。那么,他的可扩展性怎么样呢?
- lua扩展插件,插件可以是基于service、基于route、或者是全局的。非常方便
konga-ui-cl62726.staging.ingress.mice.cc.d.xiaomi.net/#!/dashboar…