什么是 Kong
Openrestry 是一个基于Nginx 与 Lua的高性能平台,内部有大量的 Lua 库。其中ngx_lua_moudule使开发人员能使用 Lua 脚本调用 Nginx 模块。Kong 是一个 Openrestry 程序,而 Openrestry 运行在 Nginx 上,用 Lua 扩展了 nginx。所以可以认为 Kong = Openrestry + nginx + lua。Kong 有很高的扩展性,可以通过其插件机制实现扩展。
官方文档:https://docs.konghq.com/
Github:https://github.com/Kong/kong
原理
客户端请求到达 Kong,Kong 识别出是哪个 Consumer,根据路由规则将请求转发给 Service 对应的上游服务。我们来看看这个过程中涉及到的核心组件
- Consumer:代表一个应用,可以为 Consumer 定义 plugin,制定其请求规则。
- Route:客户端与服务匹配的规则,是 Kong 的入口,一旦匹配 Route 规则,则将其代理到与其关联的 Service,一个 Route 对应一个 Service,一个 Service 有多个 Route
- Service:管理我们的 API 或者 Upstream Server,Service 主要属性是 url,端口,协议等
- Upstream:位于 Kong 之后的服务/API,多实例部署实现负载均衡
- Plugin:提供高级功能并扩展 Gateway。例如身份认证,速率限制等。
安装 Kong
官方文档:https://konghq.com/install/#kong-community
大家可以安装企业版或者开源版,我这次安装企业版,但只使用其中的开源功能
#拉镜像
docker pull kong/kong-gateway:2.6.0.0-alpine
#打标签
docker tag kong/kong-gateway:2.6.0.0-alpine kong-ee
#创建网络
docker network create kong-ee-net
#运行数据库容器
docker run -d --name kong-ee-database --network=kong-ee-net -p 5432:5432 -e "POSTGRES_USER=kong" -e "POSTGRES_DB=kong" -e "POSTGRES_PASSWORD=kong" postgres:9.6
#数据库迁移
docker run --rm --network=kong-ee-net -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-ee-database" -e "KONG_PG_PASSWORD=kong" -e "KONG_PASSWORD={PASSWORD}" kong-ee kong migrations bootstrap
#运行 Kong
docker run -d --name kong-ee --network=kong-ee-net -e "KONG_PROXY_LISTEN=0.0.0.0:8000,0.0.0.0:9080 http2" -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-ee-database" -e "KONG_PG_PASSWORD=kong" -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" -e "KONG_ADMIN_GUI_URL=http://{HOSTNAME}:8002" -p 8000:8000 -p 8443:8443 -p 8001:8001 -p 8444:8444 -p 8002:8002 -p 8445:8445 -p 8003:8003 -p 8004:8004 -p 9080:9080 kong-ee
安装可视化界面 Konga
官方源码:https://github.com/pantsel/konga
docker pull pantsel/konga
docker run -d -p 1337:1337 --network kong-ee-net -e "TOKEN_SECRET=kongtoken" -e "DB_ADAPTER=postgres" -e "DB_HOST=kong-ee-database" -e "DB_USER=kong" -e "DB_PASSWORD=kong" --name konga pantsel/konga
访问 localhost:1337,新建用户,登录后创建连接:test/http://192.168.43.94:8001,指定 kong api 的端口 8001
Kong 代理 HTTP 服务
我们用的演示项目是 https://github.com/cysnet/gateway-aspnetcore-demo,其中包含以下内容
- Http 服务:Server1 与 Server2
- Grpc 服务:GrpcService1 与 GrpcService2
- Grpc 客户端:GrpcClient
- IdentityServer4 服务:Idstest
- 日志服务:LogServer
1.代理 Http 服务我们用 Server1,启动 Server1
2.通过 admin api 在 Kong 中创建 Service,也可使用可视化界面 Konga 创建
POST http://192.168.43.94:8001/services --data name=server1 --data url='http://192.168.43.94:5000’
3.通过 admin api 创建路由,也可使用可视化界面 Konga 创建
http://192.168.43.94:8001/services/server1/routes --data 'paths[]=/http1'--data name=http1
4.测试
Kong 代理 Grpc 服务
1.代理 Grpc 我们用 GrpcService1,启动 GrpcService1
2.通过 admin api 在 Kong 中创建 Service,也可使用可视化界面 Konga 创建
POST 192.168.43.96:8001/services --data name=gserver1 --data protocol=grpc --data host=192.168.43.94 --data port=6001
3.通过 admin api 创建路由,也可使用可视化界面 Konga 创建
POST 192.168.43.94:8001/services/gserver1/routes --data protocols[]=grpc --data name=r-gserver1 --data paths[]=/greet
4.测试,运行 GrpcClient
Kong 负载 Http 服务
1.启动 Server1 与 Server2
2.通过 admin api 在 Kong 中创建 upstreams,也可使用可视化界面 Konga 创建
POST http://192.168.43.94:8001/upstreams --data name=u-http1
3.为 u-http1 创建 target,指向 server1 与 server2
POST http://192.168.43.94:8001/upstreams/u-http1/targets --data target='192.168.43.94:5000’
POST http://192.168.43.94:8001/upstreams/u-http1/targets --data target='192.168.43.94:5001'
4.修改 http1 service 的指向,让其指向 u-htttp1 这个 upstream
PATCH http://192.168.43.94:8001/services/server1 --data host='u-http1’
5.测试,调用以下 api
http://192.168.43.94:8000/http1/Name
Kong 负载 Grpc 服务
1.启动 GrpcService1 与 GrpcService2
2.通过 admin api 在 Kong 中创建 upstreams,也可使用可视化界面 Konga 创建
POST http://192.168.43.94:8001/upstreams --data name=u-gserver1
3.为 u-gserver1 创建 target,指向 GrpcService1 与 GrpcService2
POST http://192.168.43.94:8001/upstreams/u-gserver1/targets --data target='192.168.43.94:6001’
POST http://192.168.43.94:8001/upstreams/u-gserver1/targets --data target='192.168.43.94:6002'
4.修改 gserver1 service 的指向,让其指向 u-gserver1 这个 upstream
PATCH http://192.168.43.94:8001/services/gserver1 --data host=‘u-gserver1’
5.测试,运行 GrpcClient
集成 IdentityServer4 实现 JWT 认证
1.给 server1 开启 jwt 插件
POST http://localhost:8001/services/server1/plugins -d “name=jwt ” –d “config.key_claim_name=client_id”
2.创建 consumer
POST localhost:8001/consumers -d "username=c-server1"
3.获取 ids4 证书公钥与私钥
openssl pkcs12 -in chester.pfx -nocerts -nodes -out private_pc.key
从密钥对中提取私钥(头部格式:-----BEGIN RSA PUBLIC KEY-----)
openssl rsa -in private_pc.key -out private.pem
从密钥对提取公钥(头部格式:-----BEGIN PUBLIC KEY-----)
openssl rsa -in private_pc.key -pubout -out public.key
4.为 C-server1 创建凭证
POST localhost:8001/consumers/c-server1/jwt -d "algorithm=RS256" -d "key=big_cat" -d "secret=xxxxxx" -d "rsa_public_key=xxxxxxxxx“
5.启动 id4test 获取 jwttoken
6.调用 api 验证 token
RateLimit 限流插件
POST http://<admin-hostname>:8001/plugins --data name=rate-limiting --data config.minute=5 --data config.policy=redis --data redis_host=192.168.43.102 --data limit_by=ip –data redis_password=123456
多次调用触发则触发限流
Cache 插件
POST http://localhost:8001/plugins --data name=proxy-cache --data config.content_type="text/plain; charset=utf-8" --data config.cache_ttl=30 --data config.strategy=memory
多次调用 X-Cache-Status=Hit 则命中缓存成功
日志插件
启动 LogServer
开启日志插件
POST http://localhost:8001/services/server1/plugins --data "name=http-log" --data "config.http_endpoint=http://192.168.43.94:5555/Log" --data "config.method=POST"
请求 http://192.168.43.94:8000/http1/Name,查看 LogServer 输出