Kong API 网关分享

509 阅读10分钟

Kong API 网关分享

一、业务背景

1.1、从“巨石应用”到“微应用”

这里需要一个单体应用,随着版本迭代、业务增多,发展到巨石应用。而我通过对巨石应用改造,将项目松散解耦,过渡到微应用。顺便提一下微应用的好处,巨石应用的弊端。

巨石应用

  • 项目体积庞大
  • 编译部署时间过长
  • 开发效率低下
  • 项目耦合严重,牵一发而动全身

微应用的架构设计

微应用的架构设计,本质上是应用拆分和组合。对比Nginx方案和新方案的优劣,引出微服务网关的愿景。

微服务的核心是应用拆分与组合,一般是按业务拆分应用。微应用系统架构如下:

1.2、微服务网关的愿景

细分微服务愿景,展开将对微服务网关的终极诉求。

应用的拆分与组合,一般可以通过Nginx来实现,但Nginx方案不够完美,有以下问题:

  • 前端不能享受SPA(单页面应用)的体验
  • 应用隔离很完美,应用之间数据共享比较麻烦。比如共用侧导航、消息通信
  • 类似限流,下线服务,禁IP等操作需要SRE协助修改静态配置文件,不够灵活
  • 鉴权代码要写在业务代码里,不好复用,业务代码不够纯粹,存在代码冗余。

微前端采用icestark、qiankun等框架做应用组合和分发,这里不再赘述。

微服务可以采用API网关来统一做服务的入口管理,统一分发服务,进行限流、鉴权、监控、日志、缓存等操作。客户端请求,必须通过API网关,隐藏真实的后端服务地址。确保后端的安全性。

网关应具备以下功能

  • 性能:API高可用,负载均衡,容错机制。
  • 安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
  • 日志:日志记录(spainid,traceid)一旦涉及分布式,全链路跟踪必不可少。
  • 缓存:数据缓存。
  • 监控:记录请求响应数据,api耗时分析,性能监控。
  • 限流:流量控制,错峰流控,可以定义多种限流规则。
  • 灰度:线上灰度部署,可以减小风险。
  • 路由:动态路由规则。

除此之外,还希望有以下功能:

  1. 适合RD。通过RESTFul API就可以配置Nginx转发
  2. 高扩展性。可以把路由,安全,限流,缓存,日志,监控,重试,熔断等都放到 API 网关来做,然后服务层就完全脱离这些东西,纯粹的做业务,也能够很好的保证业务代码的干净,不用关心安全,压力等方面的问题。
  3. 高性能。有一定容错机制、负载均衡能力。

二、技术选型

讲解一下公司内部的系统,再分析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、网关对比

  1. Apisix 不支持mysql
  2. Spring cloud GateWay 与其它语言结合比较麻烦
  3. NodeJS 应用较少

三、项目实战

讲下如何部署kong和konga,如何开发kong插件

3.1、基于MICE部署kong + konga,数据库用mysql

  1. 首先创建数据库,数据库名kong和konga,分别做kong和konga的数据存储。
  2. 登录mice个人账号,参考:cloud.mioffice.cn/product/doc…
  3. 初始化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
  1. 启动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
  1. 访问http://localhost:8001,查看kong配置项
  2. 通过http://localhost:8001管理API,或者搭建konga可视化界面管理API
  3. 访问http://localhost:8000/{route},验证代理是否成功
  4. 初始化konga数据库
docker run --rm konga:1.0.1 -c prepare -a mysql -u mysql://root@mysql_host/konga
  1. 运行konga
docker run -p 1337:1337 -e "DB_ADAPTER=mysql" -e "NODE_ENV=production" --name konga konga:1.0.1
  1. 访问http://localhost:1337,注册konga管理员账号,登录进去
  2. 添加kong网关链接,然后配置services、routes、upstreams、插件等。

3.2、开发kong插件

Nginx Lua执行步骤

kong插件文件结构

  1. 文件名、文件目录结构是固定,plugin名字可以调整
  2. handler.lua 一个需要实现的接口,其中每个方法会在请求/连接的生命周期中运行
  3. schema.lua 保存插件的配置项,以便用户只能输入有效的配置值
  4. kong-plugin-*-version.rockspec,用于luarocks编译打包,修改相应的插件名字即可。
  5. 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
  1. Kong本身依赖Nginx、OpenResty、Lua,依赖比较多,由于kong本身不需要更改,我们直接用docker镜像部署,而需要扩展的功能则通过插件来引入,kong镜像一般不会改。
  2. 那么本地开发插件方便吗?首先,在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网关对网络请求的几乎是无影响的。那么,他的可扩展性怎么样呢?

  1. lua扩展插件,插件可以是基于service、基于route、或者是全局的。非常方便

konga-ui-cl62726.staging.ingress.mice.cc.d.xiaomi.net/#!/dashboar…