自從在Go 1.11和更高版本中引入了Go的新的依賴管理系統(tǒng)以來,GoLang開發(fā)人員已經(jīng)接受了包版本控制解決方案。這樣做的用戶可以使用GoCenter存儲庫中的 不可變 公共Go 模塊,并通過更健壯、更可靠的Go Pipeline獲得更快的構(gòu)建速度。
但是,將現(xiàn)有的項目轉(zhuǎn)換為使用Go Module并不總是很容易,尤其是如果該項目已經(jīng)嘗試過GoLang的其他包管理解決方案時。
為了幫助GoLang社區(qū)正確地使用Go Module,我們將使用開源的etcd項目(Kubernetes使用的鍵值數(shù)據(jù)存儲)作為示例。這是一個最佳實踐的實際示例,因為它足夠復(fù)雜,可以展示一些常見的實踐
Go 項目依賴管理痛點分析
傳統(tǒng)GO項目進(jìn)行第三方模塊依賴時,往往是去下載第三方源碼,這種方式將存在以下常見問題:
- 性能及穩(wěn)定性:每次下載從各大VCS系統(tǒng)下載源碼性能低,依賴網(wǎng)絡(luò)環(huán)境,穩(wěn)定性差
- 一致性&可重復(fù)性:容易收到依賴源的影響,我們往往在感知不到模塊提供方的改動時,就下載了新版的代碼,兩次依賴某模塊得到的依賴不一致,往往造成前一秒還行,下一秒構(gòu)建失敗的情形,尤其在持續(xù)集成系統(tǒng)中
- 協(xié)作:源碼方式模塊基本無版本概念,或不是語義類型,多團(tuán)隊協(xié)作困難
基于以上問題及痛點,建議轉(zhuǎn)換為Go Module 模式管理Go 項目依賴。附Go Module 基于Go Proxy進(jìn)行依賴下載的原理圖:

應(yīng)用Go Module方式后可以獲得以下收益:
- 可用性(標(biāo)簽tag可以從VCS中刪除)
- 不變性(可以在VCS中進(jìn)行更改)
- 快速:(沒有g(shù)it克隆,沒有計算元數(shù)據(jù),調(diào)用更少,性能好)
- 本地統(tǒng)一存儲緩存($GOPATH/pkg /mod/cache)
Go模塊轉(zhuǎn)換最佳實踐
我們以ETCD項目為例進(jìn)行轉(zhuǎn)換,這個轉(zhuǎn)換過程已通過測試用例的驗證,可以到該項目中的 Pull Request 中查看
步驟一:準(zhǔn)備go.mod文件
對于以前從未使用過模塊的項目(沒有g(shù)o.mod 文件),或者任何現(xiàn)在不推薦的依賴項管理解決方案,這個過程都非常簡單。您只需要在項目的根目錄中運行g(shù)o mod tidy。這將生成一個新的、已填充好該項目依賴描述的go.mod文件。
但是,如果項目使用了那些較老的解決方案之一,比如dep、glide、govendor或godep,那么您將需要運行g(shù)o mod init來生成填充的go.mod文件。該命令支持舊格式中依賴項描述。
etcd項目確實有一個go.mod文件,盡管它從未在項目的構(gòu)建系統(tǒng)中啟用。問題是模塊名稱沒有正確的版本標(biāo)識符,因為當(dāng)前版本標(biāo)記是v2+。由于 語義化導(dǎo)入版本控制 的影響,需要更改為v3。
其包括執(zhí)行以下過程:
1. 更新etcd的go.mod文件以修正模塊名稱,使其包含v3后綴。

2. 更新所有代碼中的Import以包含版本號。我們編寫了一個腳本,以便更容易地修改所有引用。完成后,此更改如下:

步驟二 : 啟用Go模塊
要使go客戶端能夠使用go module,需要設(shè)置GO111MODULE=on
正如我們所指出的,etcd項目已經(jīng)設(shè)置了go.mod文件,有人可能認(rèn)為這已經(jīng)完成了。但它沒有,而該環(huán)境變量這種缺失證實了該項目還沒有使用go module。
注意:從Go 1.13開始,這一步將不再需要,因為Go Module將在默認(rèn)情況下啟用
步驟三 : 更新測試中的導(dǎo)入
在上面的過程中,我們對組成etcd主模塊的go.mod文件進(jìn)行了更新,以使用v3版本標(biāo)記?,F(xiàn)在主模塊被標(biāo)記為v3,我們還需要更新etcd項目的測試用例中的Import引用v3,以確保它們導(dǎo)入了主模塊的正確版本。
步驟四 : 其他更新
在這些更改之后,您可能希望保持良好的狀態(tài)—畢竟,應(yīng)用程序模塊現(xiàn)在已經(jīng)全部轉(zhuǎn)換為使用go module,并使用正確的版本標(biāo)記。
不過沒那么快。一旦你開始運行測試,你會發(fā)現(xiàn)兩個額外的場景需要處理:
1. etcd使用了諸如golint、gosimple、staticcheck、ineffassign等靜態(tài)分析工具,但其中一些工具沒有模塊意識,無法識別模塊路徑,而無法通過必要的檢查。在etcd的這種場景下,etcd-io/etcd下并沒有v3文件夾,但是Import導(dǎo)入(或模塊路徑)包含v3,如etcd-io/etcd/v3。其他工具是模塊感知的,但必須在新版本的Go 12中可用。如果構(gòu)建系統(tǒng)在11之上,那么它們也需要遷移到12。
2. 如果使用了protobuf之類的代碼生成器。更新.proto文件,以便使用正確版本的導(dǎo)入生成代碼。
步驟五 : 加入GoCenter
在構(gòu)建過程中,您可能會注意到許多go get命令在etcd的不同階段執(zhí)行。
為了加快GoLang應(yīng)用程序的構(gòu)建時間,并確保etcd ppipeline中使用的Go Module版本的不可變性和可用性,使用GoCenter來構(gòu)建etcd
只需設(shè)置GOPROXY=https://gocenter.io。(詳細(xì)原理可看上文的Go Proxy 原理圖)
總結(jié)
正如您所看到的,將Go項目轉(zhuǎn)換為使用Go Module方式非常簡單,但是有一些細(xì)節(jié)可能會減慢您的速度。通過選擇這個具有豐富場景的項目來演示這個過程,我們相信我們達(dá)到了大多數(shù)需要處理的場景,為您提供了一個很好的示例,覆蓋了您可能面臨的情況。