Kong - 插件开发

环境:

kong 是用 rpm 方式安装的。 LuaRocks as it is installed along with Kong

[root@localhost kong-plugin-huidu-master]# luarocks --version
/usr/local/bin/luarocks 3.7.0

[root@localhost kong-plugin-huidu-master]# kong version
2.4.1

[root@localhost kong-plugin-huidu-master]# luarocks path --lr-path
/root/.luarocks/share/lua/5.1/?.lua;/root/.luarocks/share/lua/5.1/?/init.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua

一、下载Kong插件开发模板

下载官方插件开发模板:

git clone https://github.com/Kong/kong-plugin.git

kong插件主要有三个文件:

handler.lua 是包含插件逻辑处理相关代码。 schema.lua 包含插件的配置文件。 rockspec 文件是通过luarock安装时用的配置文件。
逻辑处理的代码根据openresty的不同处理阶段分成了不同的函数,根据插件的功能只需要在不同的函数中添加自己的业务逻辑

二、kong插件开发实践

下面是开发一个最简单的灰度发布使用的流量分发插件的全部流程。
这个插件的功能非常简单:
根据http request头中的Authorization的值将流量分发到不同的后端服务器。
插件有两个配置项:pattern和upstream,如果Authorization的值匹配pattern,那么当前请求会被代理到相应的upstream中。

2.1、代码开发

给插件起个温暖的名字,就叫huidu吧,修改模版项目中的目录名为huidu。

mv kong-plugin kong-plugin-huidu
cd kong-plugin-huidu/kong/plugins
mv myplugin huidu

修改schema.lua文件,添加插件配置代码:

local typedefs = require "kong.db.schema.typedefs"

-- Grab pluginname from module name
local plugin_name = ({...})[1]:match("^kong%.plugins%.([^%.]+)")

local schema = {
  name = plugin_name,
  fields = {
    -- the 'fields' array is the top-level entry with fields defined by Kong
    { consumer = typedefs.no_consumer },  -- this plugin cannot be configured on a consumer (typical for auth plugins)
    { protocols = typedefs.protocols_http },
    { config = {
        -- The 'config' record is the custom part of the plugin schema
        type = "record",
        fields = {
          -- a standard defined field (typedef), with some customizations
          { pattern = {type = "string", required = true, default = "^a" } },
          { upstream = {type = "string", required = true, default = "hello" } } -- adding a constraint for the value
        },
        entity_checks = {
          -- add some validation rules across fields
          -- the following is silly because it is always true, since they are both required
          { at_least_one_of = { "pattern", "upstream" }, },
          -- We specify that both header-names cannot be the same
          { distinct = { "pattern", "upstream"} },
        },
      },
    },
  },
}

return schema

修改handler.lua文件,添加插件处理逻辑:

-- If you're not sure your plugin is executing, uncomment the line below and restart Kong
-- then it will throw an error which indicates the plugin is being loaded at least.

--assert(ngx.get_phase() == "timer", "The world is coming to an end!")


-- Grab pluginname from module name
local plugin_name = ({...})[1]:match("^kong%.plugins%.([^%.]+)")

-- load the base plugin object and create a subclass
local plugin = require("kong.plugins.base_plugin"):extend()

-- constructor
function plugin:new()
  plugin.super.new(self, plugin_name)
  
  -- do initialization here, runs in the 'init_by_lua_block', before worker processes are forked

end

---[[ runs in the 'access_by_lua_block'
function plugin:access(plugin_conf)
  plugin.super.access(self)

  -- your custom code here
  local pattern = plugin_conf.pattern
  local token = kong.request.get_header("authorization")
  if token == nil then
    return 
  end
  -- 忽略大小写
  local matched = ngx.re.match(token, pattern, "joi")
  if matched then
    -- 设置upstream
    local ok, err = kong.service.set_upstream(plugin_conf.upstream)
    if not ok then
        kong.log.err(err)
        return
    end
    -- 匹配成功添加特定头部方便监控
    ngx.req.set_header("X-Kong-" .. plugin_name .. "-upstream", plugin_conf.upstream)
    ngx.req.set_header("X-Kong-" .. plugin_name .. "-pattern", plugin_conf.pattern)
  end    
  
end --]]

-- set the plugin priority, which determines plugin execution order
plugin.PRIORITY = 1000

-- return our plugin object
return plugin

huidu插件的逻辑只需要在access阶段执行就可以,可以把多余的注释和代码删掉。

2.4、安装调试

修改kong.conf文件,添加或者修改下面的配置项。注意 插件名称和安装时的名称一致

插件一般通过 luarocks 来安装,在插件根目录下执行:

luarocks make 

此编译命令依靠文件 rockspec,

ackage = "kong-plugin-huidu"  -- TODO: rename, must match the info in the filename of this rockspec!
                                  -- as a convention; stick to the prefix: `kong-plugin-`
version = "0.1.0-1"               -- TODO: renumber, must match the info in the filename of this rockspec!
-- The version '0.1.0' is the source code version, the trailing '1' is the version of this rockspec.
-- whenever the source version changes, the rockspec should be reset to 1. The rockspec version is only
-- updated (incremented) when this file changes, but the source remains the same.

-- TODO: This is the name to set in the Kong configuration `plugins` setting.
-- Here we extract it from the package name.
local pluginName = package:match("^kong%-plugin%-(.+)$")  -- "myPlugin"

supported_platforms = {"linux", "macosx"}
source = {
  url = "https://github.com/chenyoufu/kong-plugin-huidu.git",
  tag = "0.1.0"
}

description = {
  summary = "Kong is a scalable and customizable API Management Layer built on top of Nginx.",
  homepage = "http://getkong.org",
  license = "Apache 2.0"
}

dependencies = {
}

build = {
  type = "builtin",
  modules = {
    -- TODO: add any additional files that the plugin consists of
    ["kong.plugins."..pluginName..".handler"] = "kong/plugins/"..pluginName.."/handler.lua",
    ["kong.plugins."..pluginName..".schema"] = "kong/plugins/"..pluginName.."/schema.lua",
  }
}
View Code

安装成功后,插件安装在了luarocks目录kong->plugins 。然后重启kong

kong start -c kong.conf --vv

从Konga可以看到插件安装成功了:

注意:另外一种安装方式 直接修改文件方法参考:

所有插件在 /usr/local/share/lua/5.1/kong/constants.lua

插件具体位置在/usr/local/share/lua/5.1/kong/plugins

 

 直接复制插件handler\schema到plugins目录,然后加到bundle里面,重启kong即可。

 参考:https://www.freesion.com/article/33481210612/

2.5、测试

使用web管理界面konga来配置插件。创建一个service,然后在service下安装当前插件

配置项表示以a开头的全部流量走mocktest,如果没有匹配或者插件代码有错误,那么流量就走service本身配置的upstream。

curl -X GET 'http://127.0.0.1:8000/request?foo=bar&foo=baz' -H 'authorization: ApwPYjA8J1c9CVaFIBVkRyYV57k2bXfHFH9Jojs8HN2FfyEn39MzV1afG9'

curl -X GET 'http://127.0.0.1:8000/request?foo=bar&foo=baz' -H 'authorization: XApwPYjA8J1c9CVaFIBVkRyYV57k2bXfHFH9Jojs8HN2FfyEn39MzV1afG9'

不返回信息

如果插件中有语法错误,重启会失败,可以查阅日志找问题,日志位置在/usr/local/kong/logs/error.log

 

注意:

kong 插件只要编译了,就会执行对应的生命周期,不论kong是否添加改插件。 

 

参考:

https://docs.konghq.com/gateway-oss/0.14.x/plugin-development/custom-logic/

https://docs.konghq.com/gateway-oss/0.14.x/pdk/

https://github.com/Kong/kong/blob/master/kong/plugins/tcp-log/handler.lua

https://www.jianshu.com/p/3e726106dca9?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

 

posted on 2022-03-01 19:13  TrustNature  阅读(1614)  评论(0编辑  收藏  举报