小厂内部私有Go module拉取方案(续)

自从去年在公司搭建了内部私有 Go module proxy[1]后,我们的私有代理工作得基本良好。按理说,这篇续篇本不该存在:)。

日子一天天过去,Go 团队逐渐壮大,空气中都充满了“Go 的香气”。

突然有一天,业务线考虑将目前在用的gerrit[2]换成gitlab[3]。最初使用 gerrit 的原因不得而知,但我猜是想使用 gerrit 强大且独特的 code review 机制和相应的工作流。不过由于业务需求变化太快,每个迭代的功能都很多,“+2”的 review 机制到后来就形同虚设了。

如果不用 gerrit review 工作流,那么 gerrit 还有什么存在的价值呢。从管理员那边反馈,gerrit 配置起来也是比较复杂的,尤其是权限。两者叠加就有了迁移到 gitlab 的想法。这样摆在 Go 团队面前的一个事情就是如何让我们内部私有 go module 代理适配 gitlab

如果你还不清楚我们搭建私有 Go module 代理的原理,那么在进一步往下阅读前,请先阅读一下《小厂内部私有 Go module 拉取方案》[4]

适配 gitlab

回顾一下我们的私有 Go module 代理的原理图:

7a2f491a7ae0879e82fa3ebe8cd32444.png

基于这张原理图,我们分析后得出结论:要适配 gitlab 仓库,其实很简单,只需修改 govanityurls 的配置文件中的各个 module 的真实 repo 地址即可,这也符合更换一个后端代码仓库服务理论上开发人员无感的原则。

下面我们在 gitlab 上创建一个 foo repo,其对应的 module path 为 mycompany.com/go/foo。我们使用 ssh 方式拉取 gitlab repo,先将 goproxy 所在主机的公钥添加到 gitlab ssh key 中。然后将 gitlab clone 按钮提示框中给出的 clone 地址:git@10.10.30.30:go/foo.git 填到 vanity.yaml 文件中:

//vanity.yaml
  ... ...
  /go/foo:
     repo: ssh://git@10.10.30.30:go/foo.git
     vcs: git

我门在一台开发机上建立测试程序,该程序导入 mycompany.com/go/foo,执行 go mod tidy 命令的结果如下:

$go mod tidy
go: finding module for package mycompany.com/go/foo
demo imports
    mycompany.com/go/foo: cannot find module providing package mycompany.com/go/foo: module mycompany.com/go/foo: reading http://10.10.20.20:10000/mycompany.com/go/foo/@v/list: 404 Not Found
    server response:
    go list -m -json -versions mycompany.com/go/foo@latest:
    go: mycompany.com/go/foo@latest: unrecognized import path "mycompany.com/go/foo": http://mycompany.com/go/foo?go-get=1: invalid repo root "ssh://git@10.10.30.30:go/foo.git": parse "ssh://git@10.10.30.30:go/foo.git": invalid port ":go" after host

从 goproxy 返回的 response 内容来看,似乎是 goproxy 使用的 go 命令无法识别:"ssh://git@10.10.30.30:go/foo.git",认为 10.10.30.30 后面的分号后面应该接一个端口,而不是 go。

我们将 repo 换成下面这样的格式:

/go/foo:
     repo: ssh://git@10.10.30.30:80/go/foo.git
     vcs: git

重启 govanityurls 并重新执行 go mod tidy,依旧报错:

$go mod tidy
go: finding module for package mycompany.com/go/foo
demo imports
    mycompany.com/go/foo: cannot find module providing package mycompany.com/go/foo: module mycompany.com/go/foo: reading http://10.10.20.20:10000/mycompany.com/go/foo/@v/list: 404 Not Found
    server response:
    go list -m -json -versions mycompany.com/go/foo@latest:
    go: module mycompany.com/go/foo: git ls-remote -q origin in /root/.bin/goproxycache/pkg/mod/cache/vcs/4d37c02c151342112bd2d7e6cf9c0508b31b8fe1cf27063da6774aa0f53d872f: exit status 128:
        kex_exchange_identification: Connection closed by remote host
        fatal: Could not read from remote repository.

直接在主机上通过 git clone git@10.10.30.30:80/go/foo.git 也是报错的!ssh 不行,我们再来试试 http 方式。使用 http 方式呢,每次 clone 都需要输入用户名密码,不适合 goproxy。是时候让 personal token 上阵了!在 gitlab 上分配好 personal token,然后在本地建立~/.netrc 如下:

# cat ~/.netrc
machine 10.10.30.30
login tonybai
password [your personal token]

然后我们将 vanity.yaml 中的 repo 改为如下形式:

// vanity.yaml

  /go/foo:
     repo: http://10.10.30.30/go/foo.git
     vcs: git

这样再执行 go mod tidy,foo 仓库就被顺利拉取了下来。

答疑

1. git clone 错误

在搭建 goproxy 时,我们通常会在 goproxy 服务器上手工验证一下是否可以通过 git 成功拉取私有仓库,如果 git clone 出现下面错误信息,是什么问题呢?

$ git clone ssh://tonybai@10.10.30.30:29418/go/common
Cloning into 'common'...
Unable to negotiate with 10.10.30.30 port 29418: no matching key exchange method found. Their offer: diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

这里的错误提示信息其实是很清楚明了的。git 服务器端支持 diffie-hellman-group1-sha1 和 diffie-hellman-group14-sha1 这两种密钥交换方法,而 git 客户端却默认一个都不支持。

怎么解决呢?我们需要在 goproxy 所在主机增加一个配置.ssh/config:

// ~/.ssh/config
Host 10.10.30.30
    HostName 10.10.30.30
    User tonybai
    Port 29418
    KexAlgorithms +diffie-hellman-group1-sha1

    IdentityFile ~/.ssh/id_rsa

有了这条配置后,我们就可以成功 clone。

2. 使用非安全连接

有些童鞋使用这个方案后会遇到下面问题:

$go get mycompany.com/go/common@latest
go: module mycompany.com/go/common: reading http://10.10.30.30:10000/mycompany.com/go/common/@v/list: 404 Not Found
    server response:
    go list -m -json -versions mycompany.com/go/common@latest:
    go list -m: mycompany.com/go/common@latest: unrecognized import path "mycompany.com/go/common": https fetch: Get "https://mycompany.com/go/common?go-get=1": dial tcp 127.0.0.1:443: connect: connection refused

首先,go get 得到的服务端响应信息中提示:无法连接 127.0.0.1:443,查看 goproxy 主机的 nginx access.log,也无日志。说明 goproxy 没有发起请求。也就是说问题出在 go list 命令这块,它为什么要去连 127.0.0.1:443?我们的代码服务器使用的可是 http 而非 https 方式访问。

这让我想起了 Go 1.14 中增加的 GOINSECURE,go 命令默认采用的是 secure 方式,即 https 去访问代码仓库的。如果不要求非得以 https 获取 module,或者即便使用 https,也不再对 server 证书进行校验,那么需要设置 GOINSECURE 环境变量,比如;

export GOINSECURE="mycompany.com"

这样再获取 mycompany.com/...下面的 go module 时,就不会出现上面的错误了!


“Gopher 部落”知识星球[5]旨在打造一个精品 Go 学习和进阶社群!高品质首发 Go 技术文章,“三天”首发阅读权,每年两期 Go 语言发展现状分析,每天提前 1 小时阅读到新鲜的 Gopher 日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于 Go 语言生态的所有需求!2022 年,Gopher 部落全面改版,将持续分享 Go 语言与 Go 应用领域的知识、技巧与实践,并增加诸多互动形式。欢迎大家加入!

d4fe0a8bf6154cdb78fb4050fe5af781.png

df0a21ca605ef83233954f70acc5b7ed.png

Gopher Daily(Gopher 每日新闻)归档仓库 - https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx

  • 博客:tonybai.com

  • github: https://github.com/bigwhite

57e233cce971dbf82153e61aa6b9180f.png

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

参考资料

[1] 

搭建了内部私有 Go module proxy: https://tonybai.com/2021/09/03/the-approach-to-go-get-private-go-module-in-house

[2] 

gerrit: https://www.gerritcodereview.com

[3] 

gitlab: https://about.gitlab.com

[4] 

《小厂内部私有 Go module 拉取方案》: https://tonybai.com/2021/09/03/the-approach-to-go-get-private-go-module-in-house

[5] 

“Gopher 部落”知识星球: https://wx.zsxq.com/dweb2/index/group/51284458844544

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值