介紹
在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-tool
Docker鏡像對其進行編譯,如下所述。
前置條件
使用Go插件:
- 您需要可執行文件如
go-pluginserver
。將其安裝在中/usr/local/bin/
。如果要在其他任何地方使用,請將go_pluginserver_exe變量名設置在
Kong配置文件中並且值是他的完整路徑。 - 將
go_plugins_dir
Kong配置文件中的變量設置為有效目錄。默認"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
- 所有的標准庫(比如
fmt
,rpc
,reflect
,等) - OS的庫,例如
libpthread
,libc
,ld-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) {
…
}
你可以定義事件的方法是Certificate
,Rewrite
,Access
,Preread
和 Log
。它們的簽名都是相同的。
go-pdk
包
添加"github.com/Kong/go-pdk"
到導入的程序包。kong
事件處理程序方法上收到的指針是Go PDK函數的入口點。這些功能大多數都與Lua PDK中的相應功能相同。
有關Go PDK的參考文檔,請參見go-pdk godoc頁面。