Go依赖引入私有化代码仓库

背景

公司内部一个产品是一个项目,项目中无论是公共基础库还是工具封装库,都只是一个文件夹。

如项目PRO_FIRST目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
.PRO_FIRST
├── common
│   ├── XXX
├── util
│   ├── AAA
│   ├── BBB
│   ├── CCC
├── sys
│   ├── PPP
│   └── main.go
├── go.mod
├── go.sum
├── ...

如果只有一个产品(项目)还好,然而公司内部还有很多PRO_SECONDPRO_THIRD等等产品。

而这些产品对于common/util这种库是公用的,目前的公司内部就是直接在每个产品项目中都粘贴一份common/util的代码来使用。

我认为,这就是代码管理的经典”Bad Case”!!!

分析

理想流程:

  • 首先,common和util可以拆出两个独立的包 ——在gitlab仓库中,这两个包应该是独立的项目;
  • 其次,每个产品项目都应该使用go import来引入这些库项目 ——在操作层面与引入第三方mod行为一致;

回顾一下引入第三方mod的流程:

  1. 执行 go get github.com/xxx/yyy 命令;
  2. 执行 go mod tidy 命令;

OK,那么我们的目标很清晰了,就是使得我们私有gitlab部署的库项目,也能够直接使用以上步骤引入,并直接在产品项目中使用。

前置知识

First:无密码git下载

git拉代码,主要有两种方式:ssh协议 or https/http协议

  • ssh协议来说,可以通过配置RSA密钥来达成无密码下载代码;

  • http/https协议来说,可以通过配置~/.netrc来实现无密码下载代码;

对于 go get 这类无交互命令来说,只能使用无密码下载方式,否则就会报错。

Second:go get流程

go get <URI> 命令主要分为以下流程:

  • 使用 https 协议下载:如果 <URI> 是一 gitlab.com/xxx/yyy
  1. 先请求 https://gitlab.com/xxx/yyy?go-get=1 链接,结果如下;

    1
    <meta name="go-import" content="gitlab.com/xxx/yyy git https://gitlab.com/xxx/yyy.git" />
  2. 然后 go get 命令会把 https://gitlab.com/xxx/yyy.git 代码下载下来,并保存为$GOPATH/pkg/mod/gitlab.com/xxx/yyy

  • 使用git+ssh协议下载:如果 <URI> 是一个 gitlab.com/xxx/yyy.git (没错,就是这个.git后缀)
  1. 则 go get 命令会直接走 ssh://git@gitlab.com/xxx/yyy.git 协议下载代码;

  2. 然后把代码保存为$GOPATH/pkg/mod/gitlab.com/xxx/yyy.git(注意这个.git后缀);

    这意味着你yyy项目中的go.mod文件中,必须声明为module gitlab.com/xxx/yyy.git

Third:go环境变量

  • **GOINSECURE**:这个环境变量,会把默认的https协议改为使用http协议;

  • **GOPRIVATE**:这个环境变量,会跳过CHECK_SUM过程;

问题汇总

现状说明:

  1. 公司gitlab部署在172.20.0.2机器上;
  2. gitlab部署的web端口是8888,既拉取项目时使用: git clone http://172.20.0.2:8888/xxx/yyy.git
  3. gitlab部署的ssh端口是7777,既拉取项目时使用: git clone ssh://git@172.20.0.2:7777/xxx/yyy.git

说明:

  • 问题一、二、三是使用https/http方式从gitlab拉取代码;
  • 问题四是使用ssh方式从gitlab拉取代码;

问题一

go get不支持 IP:Port 访问

1
2
3
4
# 命令行报错如下

> $ go get 172.20.0.2:8888/xxx/yyy
go: malformed module path "172.20.0.2:8888/xxx/yyy": invalid char ':'

解决方案

  • 本地/etc/hosts配置虚拟域名

    1
    2
    3
    # /etc/hosts文件中新增

    127.0.0.1 futuredark.run
  • 使用ssh的隧道功能做本地端口转发

    1
    2
    3
    4
    5
    # 执行下列命令,会在后台监听本地80端口,并转发到目标远程机器web端口上
    sudo ssh -L 80:172.20.0.2:8888 -N -f <user>@127.0.0.1

    # 执行下列命令,会在后台监听8022端口,并转发到目标远程机器ssh端口上
    sudo ssh -L 8022:172.20.0.2:7777 -N -f <user>@127.0.0.1
  • 配置ssh的~/.ssh/config来实现模拟默认ssh行为

    1
    2
    3
    4
    # 后续使用`ssh://futuredark.run/...`协议拉取代码时就会默认连接到8022端口

    Host futuredark.run
    Port 8022

最终效果

1
2
3
# 由本地转发,实际访问的是 `172.20.0.2:8888`

> $ go get futuredark.run/xxx/yyy

问题二

go get默认使用https,而公司gitlab只部署了http协议

1
2
3
4
# 命令行报错如下

> $ go get futuredark.run/xxx/yyy
go: unrecognized import path "futuredark.run/xxx/yyy": https fetch: Get "https://futuredark.run/xxx/yyy?go-get=1": dial tcp 127.0.0.1:443: connect: connection refused

解决方案

1
2
3
# 设置go全局变量GOINSECURE,该变量会控制go get使用http协议,而不是https协议。

go env -w GOINSECURE="futuredark.run"

最终效果

1
2
3
# 此时就会默认使用http协议发请求

> $ go get futuredark.run/xxx/yyy

问题三

go-get=1探测包的meta信息不一致

1
2
3
4
# 命令行报错

> $ go get futuredark.run/xxx/yyy
go: unrecognized import path "futuredark.run/xxx/yyy": parse http://futuredark.run/xxx/yyy?go-get=1: no go-import meta tags (meta tag 172.20.0.2:8888/xxx/yyy did not match import path futuredark.run/xxx/yyy)

排查问题

1
2
3
4
# 使用curl查看返回的具体信息

> $ curl -n http://futuredark.run/xxx/yyy?go-get=1
<html><head><meta name="go-import" content="172.20.0.2:8888/xxx/yyy git http://172.20.0.2:8888/xxx/yyy.git" /></head></html>

发现,go-get探测包的结果是有的,但是内部的content不匹配导致失败。

解决方案
在不改动gitlab部署服务的前提下,基本无解。

问题四

使用.git拉取代码成功,但是包内的module声明需要同步修改

  • Copyrights © 2019-2024 Klusfq
  • Visitors: | Views: