背景

通过 go mod 管理依赖包, 其中有几个依赖是私有仓库的, 之前下载下来没有问题。 最近刚把 Go 版本升级到13, 发现拉不下来,报 410 Gone 。(其实这个报错跟 HTTP Code 410 的语义是一样的,表示资源的访问在源服务器上不再可用 )

详细错误类似如下:

1
2
3
4
go get -v bitbucket.org/compay/lucifer
go: finding bitbucket.org/compay/lucifer latest
go: downloading bitbucket.org/compay/lucifer v0.0.0-20190921175342-61a76c096369
verifying bitbucket.org/compay/lucifer@v0.0.0-20190921175342-61a76c096369: bitbucket.org/compay/lucifer@v0.0.0-20190921175342-61a76c096369: reading https://sum.golang.org/lookup/bitbucket.org/compay/lucifer@v0.0.0-20190921175342-61a76c096369: 410 Gone

问题分析

在网上找了资料, 发现确实跟 Go 的版本升级有关系。

问题的根本原因在于 Go1.13版本之后, 对 Modules 的机制做了变更。 GOPROXY 现在可以设置为以逗号分隔的代理 URL 列表,或特殊标记 direct,其默认值是 https://proxy.golang.org,direct。 当解析一个包的路径到它所所在模块时,go 命令会在列表中的每个代理服务器上连续尝试所有候选模块路径。如果代理服务器无法到达,或出现404或410以外的HTTP状态码,则会终止搜索,而不会请求其余代理服务器。

新引入了 GOPRIVATE 环境变量。 它定义不对外公开的模块路径,作为低级别的 GONOPROXY 和 GONOSUMDB 变量的默认值。而这两个变量提供了代理和通过 checksum database 进行验证的能力。

解决

有两种解决办法, 一是通过 GOPRIVATE 环境变量走内部代理, 二是通过 GONOSUMDB 环境变量

使用 GOPRIVATE

上面已经说了, 如果代理服务器无法到达, 比如访问 410 Gone 出错, 就从 GOPRIVATE 定义的代理服务器列表, 尝试继续下载依赖包。可以在自己的 ~/.bashrc (或者 ~/.zshrc) 里, 添加以下命令 :

1
export GOPRIVATE="gitlab.com/XXX,bitbucket.org/XXX,github.com/XXX"

注: 这里 XXX 修改为正确的用户名(或 Org 名)

然后再通过 go get 尝试重新拉包:

1
2
3
4
$ go get bitbucket.org/company/lucifer
go: finding bitbucket.org/company/lucifer latest
go: downloading bitbucket.org/company/lucifer v0.0.0-20190921175342-61a76c096369
go: extracting bitbucket.org/company/lucifer v0.0.0-20190921175342-61a76c096369

使用 GONOSUMDB

没有做过尝试, 具体可以参考这篇论文: Proposal: Secure the Public Go Module Ecosystem

简单来讲, 就是定义 GONOSUMDB 变量:

1
export GONOSUMDB="gitlab.com/XXX,bitbucket.org/XXX,github.com/XXX"

注: 这里 XXX 修改为正确的用户名(或 Org 名)

总结

本文整理了如何解决 go mod下载依赖报410 Gone 错误的问题。 这个问题只在 Go1.13 版本之后引入的, 所以在升级系统上一些软件后, 发现行为表现跟之前不一样,或者运行出错, 大概率是软件的变更引起的。 实际上线上的故障绝大部分也是变更引起的, 对应变更引起的问题, 需要更快地找到变更的点或者发现, 以快速响应。

参考

  1. go modules in version 1.13
  2. Proposal: Secure the Public Go Module Ecosystem
  3. go private repo - answer from Stackoverflow
  4. Provying a checksum dateabase API