kong golang 插件开发

介绍

在Kong 2.0之前,Lua是唯一支持编写Kong插件的语言,并且仍然是开发和扩展Kong的主要方法。Go插件支持的新增功能使Kong用户可以进入Go生态系统。例如,有些数据库(例如MS SQL Server)没有很好的Lua客户端库,但Go很好地支持了这些数据库。Go插件可以直接访问此类服务器,而无需传递Kong的Lua代码。

结构

Go PDK完全基于用Go编写的单独过程。您可以命名一个go-pluginserver作为Kong的启动进程,并打开一个通讯通道以在它们之间传递事件和函数调用。这意味着Go插件可以在真实的Go环境中运行,并且可以使用Go功能,例如goroutine,I / O,IPC等。

注意:这也意味着对PDK函数的任何调用都必须转移到Kong流程中,然后再返回。

Go插件是使用-buildmode=plugin标志编译的,该标志允许插件服务器动态加载它们。为了遵守Go严格的链接兼容性检查,必须使用kong/go-plugin-toolDocker镜像对其进行编译,如下所述。

前置条件

使用Go插件:

  • 您需要可执行文件如go-pluginserver。将其安装在中/usr/local/bin/。如果要在其他任何地方使用,请将go_pluginserver_exe变量名设置在Kong配置文件中并且值是他的完整路径。
  • go_plugins_dirKong配置文件中的变量设置为有效目录。默认"off"值禁用Go支持。
  • 将已编译的Go插件添加到上一步中指定的目录中。
  • 通过管理API,数据库或声明性文件以通常方式添加插件设置。通过其文件名(不带.so后缀)引用插件。

编写自己的Go插件:

  • 具有Kong开发环境。
  • 拥有kong/go-plugin-tool:<version> docker镜像<version>应该是与kong相同的版本。

发展历程

环境一致性约束

Golang开发以较低的入门障碍和易于部署而闻名。即使用Go编写的复杂程序也可以作为单个可执行文件分发,您可以将其复制到任何地方并直接运行。

为了实现这一点,编译器默认情况下会生成静态链接的可执行文件。这种选择的一个重大缺点是,这使得扩展“完成的” Go程序非常困难。有几种方法可以解决此限制,但是大多数方法都涉及某种形式的进程间通信。由于语言和基本库都对此提供了很好的支持,因此通常这是一个很好的解决方案,但并非总是如此。

在其他语言中,为Kong选择的扩展策略很常见:插件是动态加载的模块。为此,可执行文件和插件依赖于系统库,而不是生成完全静态的程序。

这是Golang中相对较新的功能,在工具和可部署性方面有一些粗略的优势。特别是,加载的可执行文件(go-pluginserver在我们的例子中)和插件必须具有完全相同的链接行为,这一点至关重要。这至少涉及:

  • 任何常用库的相同版本,包括:
    • Kong/go-pdk
    • 所有的标准库(比如fmtrpcreflect,等)
    • OS的库,例如libpthreadlibcld-xxxx等。
  • 与Go编译器完全相同的版本。
  • 相同的Go环境变量,例如$GOROOT$GOPATH

公共库版本兼容性由go.mod依赖项管理部分处理,但这会在环境变量要求方面引入更复杂的问题。

例如,evironment变量$GOPATH是一个现实问题,不仅因为推荐的模式之一是$HOME/go,其中包括开发人员在其自己系统中的用户名,而且还因为生产构建(Dockerfile,构建脚本,CI / CD系统)很常见。使用非常不同的模式。

为了保证一致性,kong/go-plugin-tool用作Go编译器的包装。Kong发行软件包和映像使用它来编译包含的软件包go-pluginserver

开发过程

要在Go中编写Kong插件,您需要:

  • 定义结构类型以保存配置。
  • 编写一个New()函数来创建您的结构实例。
  • 在该结构上添加方法以处理事件。
  • 使用编译docker run --rm -v $(pwd):/plugins kong/go-plugin-tool:<version> build <source>
  • 将生成的库(.so文件)放入go_plugins_dir目录中。

注意:这里是个demo,请查看https://github.com/Kong/go-plugins 。

配置结构

用Lua编写的插件定义了一个架构,用来指定如何读取和验证来自数据存储区或Admin API的配置数据。由于Go是一种静态类型语言,因此所有规范都是通过定义结构体来处理的。

type MyConfig struct {
    Path   string
    Reopen bool
}

公共字段(即以大写字母开头的字段)将填充配置数据。如果希望它们在数据存储区中使用其他名称,请添加在encoding/json包装上定义的字段标签:

type MyConfig struct {
    Path   string `json:my_file_path`
    Reopen bool   `json:reopen`
}

New() 初始化

您的插件必须定义一个名为New的函数,该函数创建此类型的实例并以形式返回interface{}。在大多数情况下,就是这样:

func New() interface{} {
    return &MyConfig{}
}

您可以向结构中添加更多字段,这些字段将被传递,但是不能保证配置实例的寿命或数量。

处理事件

要处理Kong事件,请在您的配置结构中定义相关方法。例如,要处理“访问”事件,请定义如下函数:

func (conf *MyConfig) Access (kong *pdk.PDK) {
    …
}

你可以定义事件的方法是CertificateRewriteAccessPreread和 Log。它们的签名都是相同的。

go-pdk 包

添加"github.com/Kong/go-pdk"到导入的程序包。kong事件处理程序方法上收到的指针是Go PDK函数的入口点。这些功能大多数都与Lua PDK中的相应功能相同。

有关Go PDK的参考文档,请参见go-pdk godoc页面。

上一篇:Kong安装教程


下一篇:API网关Kong使用指南 —— 目录