18 September 2018

IMG-THUMBNAIL

Golang 在 1.11 开始支持 module,终于不用把依赖包上传了。

初始化

go mod init

把生成好的 go.mod 和 go.sum 提交到代码仓库。

如果要开启 module,需要设置环境变量:

export GO111MODULE="on"

下载外网代码

执行打包脚本,发现报了一堆报错:

go: golang.org/x/sys@v0.0.0-20180909124046-d0be0721c37e: unrecognized import path "golang.org/x/sys" (https fetch: Get https://golang.org/x/sys?go-get=1: dial tcp 216.239.37.1:443: connect: connection timed out)

下载超时,这也是能够预料到的。不过可以使用replace来解决,比如上面的 Go 扩展包,它没法下载,而它正好在 GitHub 上面有代码镜像,通过replace就可以到 GitHub 上面下载了。详细用法可以参考When should I use the replace directive?。不过我并没有用这个方法,这里就不展开说了。

我的方法是使用代理。

export http_proxy=10.244.255.3:7766
export https_proxy=10.244.255.3:7766

下载内网私有代码

再次执行打包脚本,因为有了代理,刚才的报错没有了,不过又有了新的报错:

cd .; git clone https://github.com/examplesite/myprivaterepo /Users/tom/go/src/github.com/examplesite/myprivaterepo
Cloning into '/Users/tom/go/src/github.com/examplesite/myprivaterepo'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
package github.com/examplesite/myprivaterepo: exit status 128

这个报错也不难看懂,下载内网包的时候没有授权,需要输入密码,而 Go 会屏蔽输入密码的操作,导致下载失败。

打开密码输入也很简单:

env GIT_TERMINAL_PROMPT=1 go get xxxx

不过这个并不是我想要的方法。一个原因是通过打包脚本输密码不方便,还有一个原因是把开发者个人密码写到打包脚本里也并不合适。

Git 支持两种授权方式,一种是 HTTPS,一种是 SSH。刚才的问题就是通过 HTTPS 下载代码的时候引起的,而通过 SSH 校验权限的话并不需要密码。那么问题来了,为什么go get是通过 HTTPS 下载代码而不是 SSH 呢?

Go 官方也给出了解释:Why does “go get” use HTTPS when cloning a repository?

公司一般喜欢只暴露80端口(HTTP)和433端口(HTTPS),其它端口会被屏蔽,包括9418(git)和22(SSH)。当使用 HTTPS 而不是 HTTP 协议时,git 会强制执行证书验证,预防中间人、窃听和篡改攻击。所以go get使用 HTTPS 协议来保证安全。

其实还有一个原因,Github 本身也推荐使用 HTTPS,大家去克隆代码的时候默认的连接都是 HTTPS 的。

如果是通过 HTTPS 下载私有代码,可以在$HOME/.netrc文件中配置密码用于授权。如果是 GitHub 用户,密码可以是access token

machine github.com login USERNAME password APIKEY

当然,go get也是可以通过 SSH 协议实现授权的。git 也支持替换的功能,可以把 HTTPS 替换成 SSH。比如要访问 Github 的私有仓库,可以把下面的代码放到~/.gitconfig里面:

[url "ssh://git@github.com/"]
	insteadOf = https://github.com/

也可以通过一条命令实现:

git config --global url."git@git.cyeam.com:".insteadOf "https://code.cyeam.com/"

SSH 授权需要用到私钥,这里就不展开讲了。默认情况下是在$HOME/.ssh/id_rsa的文件。

详细说说 insteadOf

如果你都没有填错的话,代码就可以正常下载并编译了。

但是我实际操作的时候真是费了特别大的劲,网上的搜索结果都是上面的一条替换命令,再也没有多说了,但是有一个符号错了就会有问题。

insteadOf其实就是字符串替换

比方说我的仓库,HTTPS 连接:

https://github.com/mnhkahn/gogogo.git

SSH 连接:

git@github.com:mnhkahn/gogogo.git

这两个协议区别就是一个是 https 开头,而一个是 git(注意:是git,不是你的用户名)。中间是域名,自己的私有仓库就换成仓库的域名。后面的仓库地址,这部分是完全一样的。而域名和仓库地址中间的符号,这里也有区别,一个是斜线,一个是冒号。

总结

在编译脚本里加下面的4行代码,就能通过 Go1.11 实现自动下载依赖包了,代理自己搭哦。推荐这个

export GO111MODULE="on"
export http_proxy=10.244.255.3:7766
export https_proxy=10.244.255.3:7766

# 内网似有包需要通过ssh下载
git config --global url."git@git.cyeam.com:".insteadOf "https://code.cyeam.com/"

原文链接:增加4 行代码,实现使用 Go module 在线上环境打包,转载请注明来源!

EOF