项目改用GoModules管理依赖的方法和经验总结

2020-12-15 10:22:10 浏览数 (1)

Go语言官方提供的依赖包管理工具已经发布很久了,有很多大佬的文章对Go Modules做了非常详尽的介绍,比如煎鱼大佬的: Go Modules终极入门(文章链接:https://juejin.cn/post/6844903433846145038)。

今天的文章我想跟大家聊一下我们项目在从govendor迁移到Go Modules这个过程中总结的几点经验,如果你平时负责的项目早已开始使用Go Modules,这些内容可能对你来说有点小儿科。

环境变量设置

GO111MODULE

这个环境变量是Go Modules功能的开关,目前的默认值是auto,代表只要项目包含了go.mod文件的话就自动开启Go Modules。如果之前没有设置过这个变量,这一步可以直接忽略,从其他包依赖管理工具向Go Modules迁移的时候,我们需要确认一下是不是以前在环境变量中设置过GO111MODULE=off

GOPROXY

Go Modules拉取依赖软件包的默认镜像源站点是https://proxy.golang.org,由于众所周知的问题这个域名在国内访问受限,因此需要使用GOPROXY环境变量设置国内的镜像站点。

代码语言:javascript复制
GOPROXY=https://goproxy.cn

GOPRIVATE

这个环境变量主要是为项目依赖的一些公司内部的公共软件包准备的,一般是设置成代码仓库站点的域名。假如我公司所有项目都放在用GitLab搭建的内部代码仓库站点,这个站点的域名是code.lazycorp.com,那么我们就把这个环境变量设置成

代码语言:javascript复制
GOPRIVATE=code.lazycorp.com

这样设置的话,所有路径前缀为code.lazycorp.com的模块都不会再经过GOPROXY指定的镜像站点拉取模块对应的软件包,转而去code.lazycorp.com拉取软件包。

这里提一个小技巧,假如你自己开发的时候不想污染电脑系统里的全局环境变量,可以选择在GoLand里开启Go Modules支持和设置环境变量,这样在GoLand内编译运行程序时也能正常使用Go Modules。

GoLand配置截图

Replace完成版本替换

replace指令的本意是在go.mod文件里完成用一个模块版本替换已经require的模块版本的功能,比如:

代码语言:javascript复制
module code.lazycorp.com/buzz/practice // 这名是我瞎起的

go 1.13

replace(
  google.golang.org/grpc v1.33.0 => google.golang.org/grpc v1.26.0
)

require (
 google.golang.org/grpc v1.33.0
)

这里的replace指令标识了,使用grpcv1.26.0版本,替换require里声明的v1.33.0版本。

不过也正好有replace命令,才能解决好几个软件包版本兼容的问题,我遇到的软件包兼容问题主要出在EtcdgRPC上。

Etcd比较诡异,它里面的bbolt子库的模块名叫go.etcd.io/bbolt但是自己的源码使用这个库时在代码里使用的import路径却是github.com/coreos/bbolt。再加上Etcd提供的软件包与v1.30版本以上的gRPC相互之间不兼容,所以如果gRPC使用了Etcd Naming做服务发现和负载均衡,目前只能通过replace指令对这两个模块进行版本替换。

代码语言:javascript复制
replace (
 github.com/coreos/bbolt => go.etcd.io/bbolt v1.3.5
 google.golang.org/grpc v1.33.0 => google.golang.org/grpc v1.26.0
)

模块的版本控制

模块的版本号会与软件包的tag相对应,比如上面的模块引用google.golang.org/grpc v1.26.0对应于grpcGitHub上代码仓库的名叫v.1.26.0的标签。

注意标签的名字不能随便命名,比如类似v2020....的标签,Go Modules是没法识别的。

Go Modules模块的版本格式为“主版本号.次版本号.修订号”,版本号的递增规则如下:

代码语言:javascript复制
v1.26.0
 | |  |_ _  修订号
 | | 
 | |_ _ _ _ 次版本号
 |
 |_ _ _ _ _ 主版本号
  1. 主版本号:当你做了不兼容的更新时变更主版本号。
  2. 次版本号:当你做了向下兼容的功能性更新时更改次版本号。
  3. 修订号: 当你做了向下兼容的问题补丁修正时更改修订号。

测试和生产阶段的模块版本管理

假如我们对公司的公共包做了修改,那么怎么对公共包打标签呢?不能说在测试、仿真和生产阶段给都要给软件包打上不同版本的标签吧,这样代码仓库的标签管理起来容易混乱。

针对这种情况可以将版本信息追加到“主版本号.次版本号.修订号”的后面,作为延伸,比如:

代码语言:javascript复制
// 在测试分支上打标签
v1.2.30-test
// 在仿真分支上打标签
v1.2.30-pre

这样等测试通过,引用公共软件包的项目需要上线的时候,就可以在公共软件包的master分支打出v1.2.30标签,将待发布项目中go.mod文件里的引用更改成正式版本即可。

此外如果公共包的代码仓库上不存在任何标签,go get默认拉取的是主干分支最新一次commit对应版本的代码,并且在go.mod文件里为模块分配格式为 v0.0.0-主干分支最新一次commit的时间-commit哈希 这样的一个虚拟版本。

常用的命令

  • go mod init 初始化go.mod文件,一般建新项目时才会用这个命令。
  • go mod tidy 整理现有依赖,修改go.mod文件后执行会更新依赖。
  • go mod graph 查看现有的依赖结构。
  • go mod vendor 导出项目所有依赖到vendor目录 (不建议使用)。

这里列出go mod vendor命令是提醒大家,如果使用go mod vendor, 会在项目里生成一个vendor目录把所有依赖导出放到这里面。此后Go Modules在项目里会去vendor里查找引用的依赖包而不是默认的$GOPATH/pkg/mod目录。

假如我们主动更新了依赖包,还需要再次执行go mod vendor把更新导出到vendor目录,项目才能真正引用到更新后的依赖包。

所以既然开始使用Go Modules了,就应该尽量忘记vendor另外旧项目从govendor改用Go Modules时的第一步也是先把项目里的vendor目录删掉,再按照文章里的步骤进行操作

最后推广一下我自己写的Kubernetes教程,上次的文章《深入理解StatefulSet,用Kubernetes编排有状态应用》花了两个周末结果阅读惨淡。我写的Kubernetes文章都非常适合研发入门学习的啊

,大家有兴趣的话都去看看哈。

- END -

0 人点赞