作者 | 孫健波(天元) 阿裡巴巴技術專家
導讀:
go modules
是 golang 1.11 新加的特性。如今 1.13 都已經釋出了第 7 個小版本了,幾乎所有大項目均已開始使用,這自然也包括 Kubernetes 生态中的衆多項目。筆者在開發 OAM 相關項目的時候,卻發現 modules 的各項功能看似簡單,卻并沒有那麼好用,于是便想給大家分享一下使用心得,希望大家也能在最短時間内學會 modules 的使用,避免踩坑。 modules 是什麼?
簡單說就是包管理,Golang 的包管理素來以混亂著稱,以前是依賴
$GOPATH
,隻要你的代碼放在指定路徑下就好了,完全沒有“包管理”的概念。被社群吐槽了很久以後開始搞
vendor
機制,簡單來說就是代碼不光是可以放到指定路徑,還可以放在項目自身路徑的 vendor 檔案夾。這個解決的問題是:你引用的代碼包上遊變更不會直接影響你的項目,這顯然是開始關心“包版本”了。遺憾的是依舊沒有解決包管理的問題,比如不同的包依賴了同一個包的不同版本怎麼辦?版本間代碼沖突怎麼辦?
vendor
機制并沒有解決,于是圍繞
vendor/
社群就出了幾十個包管理工具,一時間百花齊放、百家争鳴、各有所長,導緻 golang 的包管理生态變得有些混亂。對這段曆史感興趣的可以閱讀下筆者曾經寫的文章《Go 包管理的前世今生》。
更有意思的是,在 go 官方社群看到包管理工具的亂象後,也做了個功能類似的工具
dep
,原理與其他各類依靠
vendor/
機制的包管理工具類似,準備對包管理做統一。當大家對
dep
工具報以期望并紛紛開始切換到
dep
工具管理依賴包的時候,go 官方又釋出了現在的 modules 機制,完全放棄了之前的
dep
工具與
vendor
機制。這樣的操作在社群引起了巨大的争議,modules 與
go get
、
go build
等官方工具生态有很好的內建,官方的意圖自然是希望抛開原有的曆史包袱,通過全新的方式拯救世界。然而實際體驗下來,卻依舊不盡如人意。
總的來說大趨勢已經是用
modules
,go1.13 也對 modules 機制做了不少工作。
言歸正傳,本文的目标是希望能用 5~10 分鐘時間帶您學會使用 go modules,然後通過 QA 的形式,描述一些常見的問題。如果希望詳細了解相關内容,也可以參考官方文檔。
初始化
modules 機制在 go 裡面的子指令是
go mod
。
modules 機制是 go 1.11 才引入的,是以開始用之前先檢查下自己的 go 版本
go version
,建議使用最新的 1.13 版本,涵蓋了 module 機制相關的較多更新和功能。
在保證 go 版本至少在 1.11 或以上之後,就要開啟一下環境變量 GO111MODULE,啟用 module 機制。
export GO111MODULE=on
或者設定為 auto 模式,這樣在 GOPATH 路徑下的項目可以不使用 module 機制。
export GO111MODULE=auto
建議加到
~/.bashrc
~/.zshrc
等配置中啟動便自動生效。
如果您的項目之前已經用 modules 管理了,那麼到此為止你本地的環境已經完成初始化了。
如果項目裡之前沒有使用 modules,切換過來也很簡單,删除原先的
vendor
檔案夾(保險起見可以移動到項目之外的地方),在項目裡執行一下初始化指令即可。
go mod init [module名稱]
包名跟以前一樣,還是跟 go path 強關聯的,比如我們的項目一般是在
http://github.com/oam-dev/oam-go-sdk
,那麼你的包名就是這個了。
go mod init github.com/oam-dev/oam-go-sdk
初始化完成後就會看見項目裡有個
go.mod
檔案。
然後通過
go mod download
就可以下載下傳所有原先
vendor
中的依賴。
日常包管理
使用了
go module
以後,你的許多指令就會與包管理內建,比如
go get
go build
go run
都會自動查找并在
go.mod
裡面更新依賴。
是以按照 Go 官方團隊的意思,一般情況下,你根本不用關心包管理的問題了。( 當然,這真的純粹隻是官方在 YY )
是以到這裡你就已經學會
go modules
了,沒超過5分鐘吧?
FAQ
實際因為 go 官方對包管理重視的太晚,各種包都沒有版本的概念,随随便便就會出現各種沖突,而且由于 go modules 實在是太自動了,是以就算你學會了怎麼用 modules,最後還是會比較頭疼。
下面我們就以 FAQ 的形式回答項目中遇到各種問題怎麼辦。
有些包由于特定網絡原因無法通路怎麼辦?
Go module 加入了代理的機制,隻要設定一個代理位址,就可以提供代理通路。阿裡雲就提供了這樣一個 go 的代理 ,是完全免費的服務。公共代理倉庫會代理并緩存go子產品,你可以利用該代理來避免 DNS 污染或其他問題導緻的子產品拉取緩慢或失敗的問題,加速你的項目建構。
設定的方式非常簡單,隻需要設定如下環境變量即可,執行指令:
export GOPROXY=https://mirrors.aliyun.com/goproxy/
go1.13 加入了 mirror 機制,可以通過
go env -w
設定 mirror,其實就是之前的 GOPROXY 做的更到位一些,執行指令:
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
逗号後面可以增加多個 proxy,最後的 direct 則是在所有 proxy 都找不到的時候,直接通路,代理通路不到的私有倉庫就可以正常使用了。
這個功能基本上是在家遠端辦公的必備工具了。
公司通過 gitlab 搭建了私有庫,二方依賴庫下載下傳不下來怎麼辦?
這個幾乎是最常見的問題,比較簡單的解決方案是 hack 一下 git 配置:
git config --global url."[email protected]:<your>/<package>.git".insteadOf "https://gitlab.your-company.com/<your>/<package>.git"
這個方案依賴你本地的
~/.ssh/id_rsa
, 這樣你就可以正常
go get
了。
Dockerfile 中建構鏡像怎麼解決私有庫的依賴包問題?
- 方案一:上述方式通過修改
,卻依賴你本地的git config
,在建構時可以通過 multistage-build 把私鑰 add 到~/.ssh/id_rsa
裡面 build,然後用後面新的 stage 生成鏡像,這樣建構的鏡像就不會包含私鑰;stage 0
- 方案二: 更為安全的方式是,在每次建構 Docker 鏡像之前,先在本地用
把包緩存下來,在 Dockerfile 建構鏡像過程中還是用 GOPATH 和 Vendor 機制來管理依賴。go mod vendor
依賴包怎麼更新指定版本?
先檢視版本:
$ go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
再更新:
$ go get rsc.io/[email protected]
go: finding rsc.io/sampler v1.3.1
go: downloading rsc.io/sampler v1.3.1
go: extracting rsc.io/sampler v1.3.1
$ go test
PASS
ok example.com/hello 0.022s
某些依賴包的位址變更導緻無法找到了怎麼辦?
go 的依賴與項目名直接相關,這就導緻如果我們使用了 github 上的項目,然後項目的維護人員突發奇想改個項目名稱,就會導緻所有依賴它的項目都無法找到依賴。
還好有 replace 的機制:
replace golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
版本沖突怎麼辦?
這就要梳理版本了,是最沒有捷徑的。一個比較簡單的辦法是把所有
go.mod
裡不需要指定版本的包全部删掉,僅指定必要的包版本,然後通過
go build
讓項目自動建構依賴包的版本。
通過 go mod graph 可以檢視具體依賴路徑:
$ go mod graph
github.com/oam-dev/oam-go-sdk github.com/go-logr/[email protected]
github.com/oam-dev/oam-go-sdk github.com/onsi/[email protected]
github.com/oam-dev/oam-go-sdk github.com/onsi/[email protected]
github.com/oam-dev/oam-go-sdk github.com/stretchr/[email protected]
github.com/oam-dev/oam-go-sdk golang.org/x/[email protected]
github.com/oam-dev/oam-go-sdk k8s.io/[email protected]
github.com/oam-dev/oam-go-sdk k8s.io/[email protected]
github.com/oam-dev/oam-go-sdk k8s.io/[email protected]
github.com/oam-dev/oam-go-sdk sigs.k8s.io/[email protected]
...
左邊是項目包,右邊是被依賴的包和版本。
如果确實存在兩個需要指定版本的包互相沖突,那就要做取舍,修改代碼,更新或降級某個包了。
本地包如何引用?
如果在代碼調試過程中,涉及到修改其他依賴項目代碼,這時候就要引用本地包,也可以采用 replace 機制:
require (
golang.org/x/crypto v0.0.0
)
replace golang.org/x/crypto v0.0.0 => ../crypto
後面這個就是個相對項目路徑的本地依賴所在路徑。
解決了上面的這些問題,基本上你就可以愉快的使用 module 功能啦。
go mod 指令一覽
go mod 裡還有一些其他功能,也在此列舉,友善大家查閱:
最後
OAM(Open Application Model)開放應用模型是阿裡聯合微軟針對雲原生應用的模型,第一次對“以應用為中心”的基礎設施和建構規範進行了完整的闡述。應用管理者隻要遵守這個規範,就可以編寫出一個自包含、自描述的“應用定義檔案”。
OAM 将應用劃分為應用元件和應用特征兩部分,應用元件是應用本身的邏輯,而應用特征則是雲上的各種通用能力(如擴縮容、監控、灰階等等),大大提升了應用建構時子產品化複用能力,将雲上的各類資源和能力都轉化為了标準化的可“聲明”對象。
同時 OAM 強調關注點分離,通過标準化的模型将應用開發不同階段的 API 進行分層,流程上先由研發定義應用元件,再由運維配置雲上的各種政策,最後由基礎設施團隊統一提供各類子產品化的能力。OAM 則在其中起着彼此協作的粘合劑作用,大大提高了應用傳遞的效率。
OAM 相關内容在 github 上完全開源,同時我們也為 Go 生态編寫了 oam-go-sdk 友善快速實作 OAM。
目前,阿裡巴巴團隊正在上遊貢獻和維護這套技術,如果大家有什麼問題或者回報,也非常歡迎與我們在上遊或者釘釘聯系。
參與方式:
- 釘釘掃碼進入 OAM 項目中文讨論群
- 通過 Gitter 直接參與讨論
- OAM 開源實作位址
- 點選 star 一下
招聘
我們也在招聘,感興趣的同學歡迎加入我們。在這裡,既有 CNCF TOC 和 SIG 聯***,也有 etcd 創始人、K8s Operator 創始人與 Kubernetes 核心維護成員組成的、國内最頂尖的 Kubernetes 技術團隊。在這裡,你将同來自全球的雲原生技術領域專家們(比如 Helm 項目的創始人、Istio 項目的創始人)密切合作,在獨一無二的場景與規模中從事 Kubernetes、Service Mesh、Serverless、Open Application Model ( OAM )等雲計算生态核心技術的研發與落地工作,在業界标杆級的平台上既賦能阿裡巴巴全球經濟體,更服務全世界的開發者使用者。
履歷投遞至 [email protected]
“阿裡巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術圈。”