Skip to content

穩定打包 Go Binary 成 Debian Package 的選擇 ​

Context ​

需求:需要準備一個穩定的方式打包某個 Go Package (在 github 上) 編出的執行檔進一個 Debian package ,因為他不在 native 的 apt repository 裡面。

例如打包成這樣

/opt/mukyu/gotoolbla/bin/gotoolbla
/opt/mukyu/gotoolbla/man/....

一開始,我是先把 Github release page 裡面的 source code pack 下載下來,搭配 shell script + CMake 處理:

GitHub release 頁面的 Source code(zip、tar.gz)下載連結

code.zip
make_deb.sh
CMakeLists.txt

雖然對於其他 c/cpp source code package ,尤其是「來源無法穩定」的 Package 或者需要後處理 (git clone with submodule) 才能編譯的 Package,這種做法還算可以。但「一般」(基本上符合 Go 版本規範)的 Golang repository, 不太有這兩個問題。「比較新」的語言: Golang 和 Rust 在 Package 處理的方向上,都預期依賴的 Library 可以從網路抓取。

方法 ​

所以,這就需要問:

  1. 既然把 source code 存放下來的原因是為了避免來源不穩,那 Go Package 是不是不需要考慮這問題?
  2. Go Package 其實仍然有其他 dependency,既然要用 zip 的方式避免網路依賴,那是不是要用 go vendor 進一步把其他 dependency 也下載下來?

所以也想了三個方式:

  • Script + Git Server
  • Source Code Zip: 就是上面的做法
  • Vendor: Source code + Go vendor + zip

Script + Git Server ​

用 Git Server 來保存 Go repository。以避免 binary file 出現在 Git Repository 的角度來看,這是最好的選擇。

假如有不少 Go Repository 需要處理,這方案應該是這三種裡面最好的?

Source Code Zip ​

某種程度上來說算是個半吊子的方式,因為 Go package 通常會用到其他 repository ,例如 go.mod 裡面那一串 require ,所以沒有辦法避免依賴外部資源。

module ...

require (

	github.com/armon/go-radix v1.0.0
	github.com/aws/aws-sdk-go v1.43.5
	github.com/bep/clock v0.3.0
    ...
)

Source Code Vendor Zip ​

go mod vendor

這樣可以把所有依賴都放在一個資料夾。

不過,假如要用 Vendor 這功能,還需要考量兩點:

  • Go Vendor 是否會被 Deprecate
  • Vendor 的功能本身意圖
  • Source Code 處理的流程

Go Vendor 是否會被 Deprecate ​

Go Vendor 是在 Go Module 功能出現之前暫時用來管理依賴的功能,是否會因為 Go Module 出現後逐漸「消失」,最後被 Golang Deprecate 掉?這很重要,假如我們使用了 Go Vendor 當作管理 Go Package 編成 Debian Package 的方式,然後 Go Vendor 在某一版消失了??那就很有問題了。

從這討論裡面: proposal: cmd/go: automatic and partial vendoring in module mode

Vendor is used because there isn't a better alternative to reviewing dependency changes alongside (and as part of the same process as) changes to one's own code.

– myitcv

或許可以推斷這功能不容易消失。

Vendor 的功能本身意圖 ​

這功能從上面來看,之後大概會被看作一個用來做 Code Review 的功能?這和我們想要的【避免依賴外部資源】意圖有不小的差距。

其次,有人提了一個 proposal: cmd/go: partial vendoring,目標是可以只把部分指定的外部依賴 Vendor 進來。但是也有人回:

Perhaps the better solution is to just stop using vendoring and instead support this requirement in another system such as a read through cache that never evicts unless explicitly told to do so.

– johnwmstevens

這的確很有說服力,畢竟把外部 Code 丟到 Git Repository 不是甚麼好的操作。

Source Code 處理的流程 ​

我們需要先下載 Source Code,然後下 go vendor ,再壓縮起來,這似乎會和原本 Source Code 有一定的距離。

總之,這方法看起來會隨著時間變成技術債。

結論 ​

推薦 Script + Git Server。

假如不太想自己架 Git Server ,並且有信任的 Git Server Provider (ex: Github, GitLab, Bitbucket …),可以把 Repository 放在上面。

參考 ​

Changelog

Just observe 👀