从版本1.3开始,kong开始原生支持gRPC了。本篇文章会讨论如何使用kong管理gRPC服务。
主要讨论2个步骤,单独的gRPC Service和Route,单独的gRPC Service和多个Route。前者配置一个能捕获全部请求的Route,它清理全部的gRPC请求到制定的upstream gRPC service;后者标明如何Route每一个gRPC方法。
注意:想要使用该功能需要开启kong的http2的代理,如果使用docker启动命令如下:
// 其中8990端口用于grpc
docker run -d --name kong \
--network=kong-net \
-e "KONG_DATABASE=cassandra" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
-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" \
-e "KONG_PROXY_LISTEN=0.0.0.0:8000 reuseport backlog=16384, 0.0.0.0:8443 ssl reuseport backlog=16384, 0.0.0.0:8990 http2 reuseport backlog=16384" \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-p 8990:8990 \
kong:latest1. 单gRPC Service & Route
创建一个Service(假设gRPC服务启动在你本地的15002端口)
// localhost上要部署有grpc服务,如果是docker部署,grpc在宿主机上,要填写宿主机地址
curl -XPOST localhost:8001/services \
--data name=grpc \
--data protocol=grpc \
--data host=localhost \
--data port=15002然后创建一个Route
$ curl -XPOST localhost:8001/services/grpc/routes \
--data protocols=grpc \
--data name=catch-all \
--data paths=/然后可以使用 github.com/grpc/grpc-j… 中的example验证该功能。(把client地址改为kong的地址)
使用上述例子中使用CustomHeaderServer验证,会发现client中收到的返回会在头文件中增加如下内容:
x-kong-upstream-latency=232,x-kong-proxy-latency=2,via=kong/2.0.02. 单gRPC Service、多Route
基于上一个例子,创建多个route,每个用于一个gRPC方法。假设protobuf文件如下:
syntax = "proto2";
package hello;
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse);
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
}
message HelloRequest {
optional string greeting = 1;
}
message HelloResponse {
required string reply = 1;
}我们希望为SayHello和LotsOfReplies单独创建route,方法如下:
// SayHello
curl -XPOST localhost:8001/services/grpc/routes \
--data protocols=grpc \
--data paths=/hello.HelloService/SayHello \
--data name=say-hello
//LotsOfReplies
curl -XPOST localhost:8001/services/grpc/routes \
--data protocols=grpc \
--data paths=/hello.HelloService/LotsOfReplies \
--data name=lots-of-replies建议直接用上面git中的RouteGuideServer测试。
3. plugins
kong的插件如何开发和集成 zhuanlan.zhihu.com/p/52402537 这篇博客里写的很清楚,除了版本有点老以外别的没问题。写插件时遇到lua语法问题可以参考:www.lua.org/manual/5.1/… 遇到PDK(kong插件开发工具包)的问题可以参考:docs.konghq.com/2.0.x/pdk/
为了调研使用插件鉴权grpc协议,我写了一个简单的demo,下载(https://github.com/Kong/kong-plugin.git),按照上面博客的步骤修改文件结构,结果如下:
├── LICENSE
├── README.md
├── kong
│ └── plugins
│ └── wangqi
│ ├── handler.lua
│ └── schema.lua
├── kong-plugin-wangqi-0.1.0-1.rockspec
修改schema.lua文件内容,增加插件的config字段,这里我们增加了一个字段叫my_keys,是个string类型。
return { no_consumer = false,
-- this plugin is available on APIs as well as on Consumers, f
ields = { my_keys = {type = "string"} },
self_check = function(schema, plugin_t, dao, is_updating)
-- perform any custom verification
return true
end}随后修改handler.lua增加鉴权逻辑
function plugin:access(plugin_conf)
local token = kong.request.get_header("mytoken")
if token == nil then
return kong.response.exit(400, "mytoken empty")
end
if token ~= plugin_conf.my_keys then
return kong.response.exit(400, "mytoken error")
end
end --]]因为是demo,这里鉴权逻辑很简单,如果请求header中的mytoken信息等于插件配置的my_keys则鉴权通过。
上面的插件集成的博客中kong是物理机部署的,当使用docker时集成方式类似:
docker run -d --name kong \
--network=kong-net \
-e "KONG_DATABASE=cassandra" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
-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" \
-e "KONG_PROXY_LISTEN=0.0.0.0:8000 reuseport backlog=16384, 0.0.0.0:8443 ssl reuseport backlog=16384, 0.0.0.0:8990 http2 reuseport backlog=16384" \
-e "KONG_PLUGINS=bundled,wangqi" \
-e "KONG_LUA_PACKAGE_PATH=/usr/local/kong-plugin-wangqi/?.lua;./?.lua;./?/init.lua;;" \
-v /Users/qiwang/workspace/kong-plugin-wangqi:/usr/local/kong-plugin-wangqi \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-p 8990:8990 \
kong:latest这里我选择的是:
- 把本地的插件源代码路径挂载到docker内部。
- 使用KONG_PLUGINS环境变量制定启动的插件名称,其中bundled是自带的插件,wangqi是刚刚新建的插件。
- 使用KONG_LUA_PACKAGE_PATH制定插件所在目录。
也可以使用博客中laurocks编译的方式集成插件,方法类似。插件集成完成后,即可验证是否满足期望。
当前待解决问题:插件开发方式不友好,只能写完插件后restart镜像看效果,后续期待更友好的开发方式。