使用 golang-plugins 時要避免的事情

使用 golang-plugins 時要避免的事情

herowk · 

https://studygolang.com/articles/17365?fr=sidebar    

這是一個創建於 2019-01-01 19:58:57 的文章,其中的信息可能已經有所發展或是發生改變。

我們正計劃開源我們的項目。其中有一些關於授權邏輯的代碼是我們公司高度定製的,我們需要在提供相同功能的情況下剔除掉這部分代碼。並且,使任何人在實現自己的授權邏輯時,不需要重新編譯所有代碼。

 

我們的代碼庫在我所鍾愛的 Go 中。在尋找可能的實現方案時,我們發現了 golang-plugins 。使用 golang-plugins,你可以通過 go build -buildmode=plugin 命令構建的文件導入函數和變量。

我們很快就爲該需求準備了一個原型實現。但是,在此期間,我們遇到了一些問題。以下是我們面臨的一些問題以及避免這些問題的方法:

1) 不同的 Go 版本

插件實現和主應用程序都必須使用完全相同的 Go 工具鏈版本構建。根據你的 Go 版本,您將收到如下錯誤:

panic: plugin.Open("simpleuser.plugin"): plugins must be built with the same version of the Go toolchain as the main application

或者

panic: plugin.Open("simpleuser.plugin"): plugin was built with a different version of package GitHub.com/alperkose/golangplugins/user

解決方法:無。

由於插件提供的代碼將與主代碼在相同的進程空間中運行,因此編譯的二進制文件應與主應用程序 100% 兼容。

2) 不同的 GOPATH

插件實現和主應用程序都必須使用完全相同的 GOPATH 構建。你會得到的錯誤是:

panic: plugin.Open("differentgopath.plugin"): plugin was built with a different version of package GitHub.com/alperkose/golangplugins/user

解決方法:使用相同的 GOPATH (官方 docker 鏡像中的 GOPATH 是:/go)。問題issue#19223 就是針對類似情況的。

示例代碼:https://github.com/alperkose/golangplugins

3) 使用 vendor 文件夾

這似乎與 #2 有點相關,但如果你在插件或主應用程序中使用 vendor 文件夾,你會得到一個非常奇怪的錯誤:

panic: interface conversion: plugin.Symbol is func() user.Provider, not func() user.Provider

如果你仔細觀察,你會發現期望 func() user.Provider 和實際 func() user.Provider 方法簽名是一樣的。這是一個非常令人困惑的錯誤,但在 1.8 版本之後的所有版本中都存在。

解決方法:在構建二進制文件時複製 vendor 文件夾中的所有內容到 gopath 中。這是一個非常 " 髒 " 的解決辦法,你需要爲插件和主應用程序都執行此操作。如果構建其中一個二進制文件必須使用 vendor 文件夾時,則無法使用 golang-plugin 解決方案。

我們的例子中,在構建階段複製 vendor 文件夾中的內容到 gopath ,然後刪除 vendor 文件夾,都是在 docker 鏡像中完成的,因此我們的本地文件夾結構在開發期間得以保持不變。

... RUN cp -r vendor/* $GOPATH/src && rm -rf vendor/ ...

問題issue#18827 是針對此類情況打開的。

示例代碼:https://github.com/alperkose/golangplugins

4)不同版本的公共依賴項

在插件中的任何依賴項應該與主應用程序中的依賴項版本相同。

同樣,由於插件提供的代碼將與主代碼在相同的進程空間中運行,因此編譯的二進制文件應與主應用程序 100 %兼容。當你編譯二進制文件時,第三方軟件包也會編譯在該二進制文件中,但如果進程空間中存在相同函數的不同版本,二進制文件將會出現錯誤。

解決方法:使用包管理器並確保依賴項是相同的版本。

你可以在這裏找到關於這個問題的評論:https://github.com/whiteboxio/flow/issues/3

5)構建靜態二進制文件

你無法將插件編譯爲靜態二進制文件。我喜歡靜態二進制文件,因爲它避免了在 docker 鏡像中有基本鏡像的要求。使用 docker scratch image 可以提供最小的 docker 鏡像並減少一個很大的依賴。當我嘗試爲插件構建靜態二進制文件時失敗了,可以在這篇文章 中找到原因。

解決方法:無。你需要使用 CGO 進行編譯,如果使用的是 docker ,則需要在 Dockerfile 中使用基本映像。


結論

我認爲 golang-plugins 還不是一個成熟的解決方案。它迫使你的插件實現與主應用程序產生高度耦合。即使你可以控制插件和主應用程序,最終結果也非常脆弱且難以維護。如果插件的作者對主應用程序沒有任何控制權,開銷會更高。

所有這些問題促使我們考慮替代方案,最後我們選擇使用 hashicorp 插件包。它基於 RPC 通信併爲我們提供了足夠的靈活性,儘管它也有自己的侷限性,但比 golang-plugins 更容易克服。

源碼

你可以在此處找到用於測試問題# 2 和# 3 的源碼:https//github.com/alperkose/golangplugins


via: https://medium.com/@alperkose/things-to-avoid-while-using-golang-plugins-f34c0a636e8

作者:Alper Köse  譯者:herowk  校對:polaris1119

本文由 GCTT 原創編譯,Go語言中文網 榮譽推出

本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,爲開源做一些自己的貢獻麼?歡迎加入 GCTT
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯繫我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在正文中標註並保留原文/譯文鏈接和作者/譯者等信息。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽


歡迎關注我們的微信公衆號,每天學習Go知識

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章