Go的前世今生

前言

最近一直在家办公,忙完了工作的东西之后,总觉得这样太过于无聊了,所以就想学点啥东西充实一下自己,这不就开始上手Go 语言了。

在网上找了几个视频,看了一遍,开始动手写,这个时候问题就来了,导入不了包!

这就很莫名其妙了,查了一通,修改http 代理、加go.mod、设置GOPATH…等等,一通折腾,项目最后可以运行了,但是我觉得还是需要再补补知识,这部这篇博客就出来了。

Go Modules

历史前言

Go 1.11 推出的模块(Modules)为 Go 语言开发者打开了一扇新的大门,理想化的依赖管理解决方案使得 Go 语言朝着计算机编程史上的第一个依赖乌托邦(Deptopia)迈进。随着模块一起推出的还有模块代理协议(Module proxy protocol),通过这个协议我们可以实现 Go 模块代理(Go module proxy),也就是依赖镜像。

Go 1.13 的发布为模块带来了大量的改进,所以模块的扶正就是这次 Go 1.13 发布中开发者能直接感觉到的最大变化。而问题在于,Go 1.13 中的 GOPROXY 环境变量拥有了一个在中国大陆无法访问到的默认值 proxy.golang.org,经过大家在 golang/go#31755 中激烈的讨论(有些人甚至将话提上升到了“自由世界”的层次),最终 Go 核心团队仍然无法为中国开发者提供一个可在中国大陆访问的官方模块代理。

为了今后中国的 Go 语言开发者能更好地进行开发,七牛云推出了非营利性项目 goproxy.cn,其目标是为中国和世界上其他地方的 Gopher 们提供一个免费的、可靠的、持续在线的且经过 CDN 加速的模块代理。可以预见未来是属于模块化的,所以 Go 语言开发者能越早切入模块就能越早进入未来。

如果说 Go 1.11 和 Go 1.12 时由于模块的不完善你不愿意切入,那么 Go 1.13 你则可以大胆地开始放心使用。本次分享将讨论如何使用模块和模块代理,以及在它们的使用中会常遇见的坑,还会讲解如何快速搭建自己的私有模块代理,并简单地介绍一下七牛云推出的 goproxy.cn 以及它的出现对于中国 Go 语言开发者来说重要在何处。

Go Modules 简介

Go modules (前身 vgo) 是 Go team (Russ Cox) 强推的一个理想化类语言级依赖管理解决方案,它是和 Go1.11 一同发布的,在 Go1.13 做了大量的优化和调整,目前已经变得比较不错,如果你想用 Go modules,但还停留在 1.11/1.12 版本的话,强烈建议升级。

GOPATH

Go modules 出现的目的之一就是为了解决 GOPATH 的问题,也就相当于是抛弃 GOPATH 了。

Opt-in

Go modules 还处于 Opt-in 阶段,就是你想用就用,不用就不用,不强制你。但是未来很有可能 Go2 就强制使用了。

“module” != “package”
有一点需要纠正,就是“模块”和“包”,也就是 “module” 和 “package” 这两个术语并不是等价的,是 “集合” 跟 “元素” 的关系,“模块” 包含 “包”,“包” 属于 “模块”,一个 “模块” 是零个、一个或多个 “包” 的集合。

Go Modules 相关属性

  • 开关环境变量: GO111MODULE
  • 辅助环境变量: GOPROXY、GONOPROXY、GOSUMDB、GONOSUMDB、GOPRIVATE
  • 辅助概念: Go module proxy 和Go checksum database
  • 主要文件: go.mod 和 go.sum
  • 主要管理子命令: go mod
  • 缓存: GLOBAL CACHING(不同项目的相同模块会在电脑上缓存一份)

go.mod

1
2
3
4
5
6
7
8
9
10
11
12
module example.com/foobar

go 1.13

require (
github.com/go-redis/redis v7.2.0
)

exclude example.com/banana v1.2.4

replace example.com/apple v0.1.2 => example.com/rda v0.1.0
replace example.com/banana => example.com/hugebanana

go.mod 是启用了 Go moduels 的项目所必须的最重要的文件,它描述了当前项目(也就是当前模块)的元信息,每一行都以一个动词开头,目前有以下 5 个动词:

  • module:用于定义当前项目的模块路径。
  • go:用于设置预期的 Go 版本。
  • require:用于设置一个特定的模块版本。
  • exclude:用于从使用中排除一个特定的模块版本。
  • replace:用于将一个模块版本替换为另外一个模块版本。
    这里的填写格式基本为包引用路径+版本号,另外比较特殊的是 go $version,目前从 Go 1.13 的代码里来看,还只是个标识作用,暂时未知未来是否有更大的作用。

go.sum

go.sum 是类似于比如 dep 的 Gopkg.lock 的一类文件,它详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go 在今后的操作中保证项目所依赖的那些模块版本不会被篡改。

1
2
example.com/apple v0.1.2 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 
example.com/apple v0.1.2/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=

我们可以看到一个模块路径可能有如下两种:

前者为 Go modules 打包整个模块包文件 zip 后再进行 hash 值,而后者为针对 go.mod 的 hash 值。他们两者,要不就是同时存在,要不就是只存在 go.mod hash。

那什么情况下会不存在 zip hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 zip hash,就会出现不存在 zip hash,只存在 go.mod hash 的情况。

GO111MODULE

这个环境变量主要是 Go modules 的开关,主要有以下参数:

  • auto: 只在项目包含了 go.mod 文件时启用 Go modules,在 Go 1.13 中仍然是默认值,详见: golang.org/issue/31857
  • on: 无脑启用 Go modules,推荐设置,未来版本中的默认值,让 GOPATH 从此成为历史。
  • off: 禁用 Go modules。

GOPROXY

这个环境变量主要是用于设置 Go 模块代理,主要如下:

  • 用于使 Go 在后续拉取模块版本时能够脱离传统的 VCS 方式从镜像站点快速拉取。它拥有一个默认:https://proxy.golang.org,direct ,但很可惜 proxy.golang.org 在中国无法访问,故而建议使用 goproxy.cn 作为替代,
    可以执行语句:go env -w GOPROXY=https://goproxy.cn,direct
  • 设置为 “off” : 禁止 Go 在后续操作中使用任 何 Go module proxy。

GOSUMDB

它的值是一个 Go checksum database,用于使 Go 在拉取模块版本时(无论是从源站拉取还是通过 Go module proxy 拉取)保证拉取到的模块版本数据未经篡改,也可以是“off”即禁止 Go 在后续操作中校验模块版本。

拥有默认值:sum.golang.org (之所以没有按照上面的格式是因为 Go 对默认值做了特殊处理)。可被 Go module proxy 代理。sum.golang.org 在中国无法访问,故而更加建议将 GOPROXY 设置为 goproxy.cn,因为 goproxy.cn 支持代理 sum.golang.org。

Go Checksum Database

Go checksum database 主要用于保护 Go 不会从任何源头拉到被篡改过的非法 Go 模块版本。

GONOPROXY/GONOSUMDB/GOPRIVATE

这三个环境变量都是用在当前项目依赖了私有模块,也就是依赖了由 GOPROXY 指定的 Go module proxy 或由 GOSUMDB 指定 Go checksum database 无法访问到的模块时的场景。

在使用上来讲,比如 GOPRIVATE=*.corp.example.com 表示所有模块路径以 corp.example.com 的下一级域名 (如 team1.corp.example.com) 为前缀的模块版本都将不经过 Go module proxy 和 Go checksum database,需要注意的是不包括 corp.example.com 本身。

Global Caching

这个主要是针对 Go modules 的全局缓存数据说明,如下:

  • 同一个模块版本的数据只缓存一份,所有其他模块共享使用。
  • 目前所有模块版本数据均缓存在 $GOPATH/pkg/mod和 ​$GOPATH/pkg/sum 下,未来或将移至 $GOCACHE/mod 和$GOCACHE/sum 下( 可能会在当 $GOPATH 被淘汰后)。
  • 可以使用 go clean -modcache 清理所有已缓存的模块版本数据

快速迁移项目至 Go Modules

  • 第一步: 升级到 Go 1.13。
  • 第二步: 让 GOPATH 从你的脑海中完全消失,早一步踏入未来。
    修改 GOBIN 路径(可选):go env -w GOBIN=$HOME/bin。
    打开 Go modules:go env -w GO111MODULE=on。
    设置 GOPROXY:go env -w GOPROXY=https://goproxy.cn,direct # 在中国是必须的,因为它的默认值被墙了。
  • 第三步(可选): 按照你喜欢的目录结构重新组织你的所有项目。
  • 第四步: 在你项目的根目录下执行 go mod init 以生成 go.mod 文件。
  • 第五步: 想办法说服你身边所有的人都去走一下前四步。

使用Go Modules 时遇到的坑

判断项目是否使用了Go Modules

1
go env

满足两个条件即可:

  • 项目中包含go.mod 文件。
  • 查看环境变量GO111MODULE 不为off 。

管理Go 的环境变量

提到 Go1.13 新增了 go env -w 用于写入环境变量,而写入的地方是 os.UserConfigDir 所返回的路径,需要注意的是 go env -w 不会覆写。

从 dep、glide 等迁移至 Go Modules

原因是因为BUG 的原因导致不经过GOPROXY ,解决办法有两种:

  • 手动创建一个 go.mod 文件,再执行 go mod tidy 进行补充。
  • 上代理,相当于不使用 GOPROXY 了。

拉取私有模块

  • GOPROXY 是无权访问到任何人的私有模块的,所以你放心,安全性没问题。
  • GOPROXY 除了设置模块代理的地址以外,还需要增加 “direct” 特殊标识才可以成功拉取私有库。

更新现有模块

1
go get -u

goproxy.cn

  • Goproxy 中国 (goproxy.cn) 是目前中国最可靠的 Go module proxy 。
  • 为中国 Go 语言开发者量身打􏰁,支持代理 GOSUMDB 的默认值,经过全球 CDN 加速,高可用,可 应用进公司复杂的开发环境中,亦可用作上游代理。
  • 由中国倍受信赖的云服务提供商七牛云无偿提供基础设施支持的开源的非营利性项目。
  • 目标是为中国乃至全世界的 Go 语言开发者提供一个免 费的、可靠的、持 续在线的且经过 CDN 加􏰀的 Go module proxy。
  • 域名已由七牛云进行了备案。

总结

这好像是我第一次在博客写到结尾进行总结,这篇文章其实大部分都是官方的话,我只是照搬了过来,但是这也让我能了解了Go 关于包管理这部分的内容了,这样也满足了。

引用

https://segmentfault.com/a/1190000020522261

个人备注

此博客内容均为作者学习与官方文档所做笔记,侵删!
若转作其他用途,请注明来源!