Kong API Gateway 自定义plugin

在网上找了好长时间, 居然都没有一个完整的手顺可以写一个kong api gateway 的自定义plugin , 有的都是一些解释和片段

所以只能自己动手查官方文档了, 下面这个例子是我自己按照官方文档整理的, 因为lua脚本和相关api都不是很熟, 所以最后内容方面只写了一个空的

关于目录结构:

目录结构是这种, 下面两个是必须有的module, 我假设你跟我一样没有太多的lua背景知识, handler.lua 和 schema.lua 是两个module的名字, 也是两个文件, 文件夹是 simple-plugin

复杂一点的可能像这样

关于如何加入自己plugin:

在/etc/kong/kong.conf文件中你可以找到下面这段

plugins = bundled

plugins = bundled,my-custom-plugin # your plugin name here

自定义插件的命名个规则为 kong.plugins.<plugin_name>.<module_name>

也就是说当你在plugins属性后面添加了你自己的plugin name之后, kong会尝试加载以kong.plugins.my-custom-plugin.<module_name>命名的lua模块

还记得一开始提到的两个必要模块名么, 所以你的模块应该类似 kong.plugins.my-custom-plugin.handler

关于kong到哪里加载这些文件:

还是/etc/kong/kong.conf, 其中属性 lua_package_path 可以用来指定存放自定义插件的路径

官方文档中这样描述这个配置

也就是说如果你配置

lua_package_path = /usr/local/custom/?.lua;;

那么你的handler.lua文件要放在

/usr/local/custom/kong/plugins/<plugin-name>/handler.lua


下面是一个完整例子, 不过这个例子里的plugin是空的, 什么都没做, 我将对应着上面的内容写

关于目录结构:

我只使用了两个文件 ( 文件内容最后再发 )

/shared/kongplugins/kong/plugins/my-custom-plugin/handler.lua

/shared/kongplugins/kong/plugins/my-custom-plugin/schema.lua

关于如何加入自己plugin:

在/etc/kong/kong.conf文件中加入对应的模块名

plugins = bundled,my-custom-plugin

关于kong到哪里加载这些文件:

在/etc/kong/kong.conf文件中加入对应的模块存放文件夹路径

lua_package_path = ./?.lua;./?/init.lua;/shared/kongplugins/?.lua;

最后把kong启动起来, 添加一个global的自定义插件吧


[root@localhost ~]# kong start

2018/11/23 10:42:57 [warn] ulimit is currently set to "1024". For better performance set it to at least "4096" using "ulimit -n"

Kong started

[root@localhost ~]# curl -X POST http://localhost:8001/plugins -d "name=my-custom-plugin"

{"created_at":1542966253000,"config":{},"id":"1029886c-6c18-4d98-9e4d-8565ec47c41e","enabled":true,"name":"my-custom-plugin"}

打开dashboard可以看到

schema.lua文件

return {

no_consumer = true,

fields = {

}

}

handler.lua文件

-- Extending the Base Plugin handler is optional, as there is no real

-- concept of interface in Lua, but the Base Plugin handler's methods

-- can be called from your child implementation and will print logs

-- in your `error.log` file (where all logs are printed).

local BasePlugin = require "kong.plugins.base_plugin"

local CustomHandler = BasePlugin:extend()

 

-- Your plugin handler's constructor. If you are extending the

-- Base Plugin handler, it's only role is to instantiate itself

-- with a name. The name is your plugin name as it will be printed in the logs.

function CustomHandler:new()

CustomHandler.super.new(self, "my-custom-plugin")

end

 

function CustomHandler:init_worker()

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.init_worker(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:certificate(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.certificate(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:rewrite(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.rewrite(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:access(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.access(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:header_filter(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.header_filter(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:body_filter(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.body_filter(self)

 

-- Implement any custom logic here

end

 

function CustomHandler:log(config)

-- Eventually, execute the parent implementation

-- (will log that your plugin is entering this context)

CustomHandler.super.log(self)

 

-- Implement any custom logic here

end

 

-- This module needs to return the created table, so that Kong

-- can execute those functions.

return CustomHandler

lua 入门(1)

在正式开始学习kong插件之前我觉得有必要系统的学习一下lua

这种小巧的胶水语言似乎在游戏脚本领域混得不错, 不过对于我这种企业应用程序员来说似乎没什么吸引力, 不过好在它确实挺容易学的

首先是安装, 从源码编译很方便的, 不用什么rpm包, 而且实际上centos7本身自带了5.1版本的lua

首先准备编译环境

yum -y install gcc automake autoconf libtool make

yum install readline-devel

然后下载源码包

http://www.lua.org/download.html

tar zxf lua-5.3.5.tar.gz

cd lua-5.3.5

进行编译安装

make linux test

make install

这个时候如果你查看lua版本 lua -v 出现还是5.1版本, 是因为/usr/bin目录下的旧版本文件没有被替换, 去搞个软连接就ok了

cd /usr/bin

mv lua lua.bak

mv luac luac.bak

ln -s /usr/local/bin/lua /usr/bin/lua

ln -s /usr/local/bin/luac /usr/bin/luac

[root@localhost bin]# lua -vLua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio[root@localhost bin]# 

helloworld

带函数的版本

lua用nil表示空值

全局变量

在lua语言中, 全局变量无需声明即可使用, 使用未经初始化的全局变量不会报错, 得到的结果是nil

当把nil赋值给全局变量时, lua会回收该全局变量

类型和值

 lua是动态类型语言, 在这种语言中, 不需要在创建变量的时候声明类型, 例如c语言, 当你使用 int a 声明一个新变量时, a 就被固定成了int , 并在内存中开辟了一个”int” 空间

lua中int这个type信息是保存在a自己的数据结构当中的, a 自己知道自己是一个 int

调用参数

参数可以通过全局变量 arg 来获得, 它是一个列表, 索引的0号位置保存的是脚本名称

lua -e “test=hello” helloworld.lua a b

arg[-3] = “lua”

arg[-2] = “-e”

arg[-1] = “test=hello”

arg[0] = “helloworld.lua”

arg[1] = “a”

arg[2] = “b”

字符串整型数那些这里就不写了,数据类型这我重点来说说 Table

Table 是lua语言中最主要, 也是唯一的一种强大的数据结构. 它可以表示数组, 集合, 记录和其他复杂结构.

lua语言也使用table来表示包和对象的从属关系, 例如 math.sin , 你可能会认为是调用了math包下的sin函数, 实际上是在math表中, sin字符串索引指向的函数

lua语言不会对表进行深克隆

a = {} — 创建一个表

value = “x” — 声明了一个字符串value, 值是x

a[value] = 10 — 这句等价于 a[“x”] = 10

当把表当成结构体使用时, 可以把索引当做成为变量的名称使用

a[“x”] = 10 等价于 a.x = 10

需要一个数组时可以使用整型数作为索引 例如 a[1] , a[2] …

遍历表

使用paris遍历表中的键值对无法保证一定是按照固定顺序的, 但是可以保证每个元素只被读取一次

如果只是数组形式的话可以使用ipairs来遍历, 此时可以保证输出顺序

数组形式还可以用和c语言类似的方式

关于安全访问

mytable = {

    x = 1,

    y = 2,

    z = 3,

    a = {

        b = 2

    },

}

 

 

if mytable~=nil 

then 

    if mytable.a~=nil 

    then

        if mytable.a.b~=nil 

        then

            print(mytable.a.b)

        end

    end

end

 

value1 = mytable and mytable.a and mytable.a.b;

print(value1)

value2 = ((mytable or {}).a or {}).b

print(value2)