Go 模块:用文件代理和 vendor 做隔离网络构建
目标
在联网的一侧用新的模块缓存下载 Go 模块,并搬到文件代理中,然后在隔离网络一侧用 GOPROXY=file:// 和 vendor 两条路构建。亲自确认把 go.sum 用作导入清单的方法,以及一行 GOFLAGS 会让 vendor 被忽略的陷阱。
为什么重要
Go 默认从 proxy.golang.org 下载,并向 sum.golang.org 询问哈希。在隔离网络中这两者都连不上。模块缓存的 cache/download 本身就是代理协议的形态,只要搬过去就成了代理,而且 go.sum 完整的话,就不必再去询问校验和数据库。这个 Pod 能访问互联网(80/443),所以承担下载端的角色,而隔离网络一侧的确认,由评分器把发往外部的 HTTP(S) 转到关闭的代理上,在封闭的状态下进行。
步骤
- 在
/root/goair/app中创建模块example.com/airgap-hello,并编写输出rsc.io/quotev1.5.2 的quote.Hello()的 main.go。用新的模块缓存GOMODCACHE=/root/goair/outside-cache下载,并一直执行到go mod tidy。 - 把
/root/goair/outside-cache/cache/download的内容搬到/srv/goproxy。 - 在隔离网络一侧的配置
/root/goair/inside.env中写入GOPROXY=file:///srv/goproxy和GOFLAGS=-mod=readonly。 - 读取该配置,在外部被封闭的状态下,用新的模块缓存
/root/goair/inside-cache构建,生成/root/goair/bin/hello-proxy。 - 在
/root/goair/app中生成 vendor 目录。 - 保持镜像中的
GOFLAGS=-mod=mod不变,用GOPROXY=off和空的模块缓存试着构建。把失败消息保存到/root/goair/gomod-trap.txt。 - 在
GOPROXY=off下,仅用 vendor 构建,生成/root/goair/bin/hello-vendor。 - 编写导入记录
/root/goair/intake.txt,把 go.sum 中模块 zip 的哈希行(不带/go.mod的行)写成모듈 버전 해시(占位符依次为模块、版本和哈希)的形式。每个哈希都必须与/srv/goproxy中的.ziphash相同。
参考
- 当前的值:
go env GOPROXY GOFLAGS GOMODCACHE GOSUMDB - 读取环境文件:
set -a; . /root/goair/inside.env; set +a - 封闭外部:
HTTPS_PROXY=http://127.0.0.1:9 HTTP_PROXY=http://127.0.0.1:9 go build ...(Go 会遵循这些变量) - 常见错误 1:用平时的模块缓存构建成功就结束。那是之前下载好的缓存帮了忙,相当于没有测试代理。
- 常见错误 2:生成了 vendor,却不确认 GOFLAGS。在这个镜像中,vendor 会被忽略。
下载端:用新的模块缓存下载依赖
在 /root/goair/app 中创建模块 example.com/airgap-hello 和 main.go,用 GOMODCACHE=/root/goair/outside-cache 下载 rsc.io/quote v1.5.2,并一直执行到 go mod tidy。
用 go mod init 创建模块,用 go get 准确下载版本。把新的缓存目录作为 GOMODCACHE,这次下载的内容就只会堆放在其中。tidy 会把被使用的依赖整理为直接依赖。
把模块缓存搬成文件代理
把 /root/goair/outside-cache/cache/download 的内容搬到 /srv/goproxy。
模块缓存的 cache/download 之下已经是代理协议的形态(@v/list、.info、.mod、.zip)。请保持目录结构原样复制。缓存中存放已解压源码的其他目录不需要。
隔离网络一侧的 Go 环境文件
在 /root/goair/inside.env 中写入 GOPROXY=file:///srv/goproxy 和 GOFLAGS=-mod=readonly。
这是 shell 可以直接读取的“名称=值”的行。file 协议后面是绝对路径,所以会有三个斜杠。-mod=readonly 可以防止构建偷偷修改 go.mod。
封闭外部,用文件代理构建
读取 inside.env,在外部被封闭的状态下,用新的模块缓存 /root/goair/inside-cache 构建,生成 /root/goair/bin/hello-proxy。
把环境文件以 export 的方式读取后,把 GOMODCACHE 设为新的目录,并把外部地址转到关闭的代理上。如果用已经下载好的缓存构建,就不算测试了代理。
第二条路:vendor
在 /root/goair/app 中生成 vendor 目录。
go mod 的子命令中,有一个是把依赖源码复制到仓库内。请看结果中是否生成了 vendor/modules.txt。
明明有 vendor 却失败的构建
保持镜像中的 GOFLAGS=-mod=mod 不变,用 GOPROXY=off 和空的模块缓存试着构建,并把失败消息保存到 /root/goair/gomod-trap.txt。
这一步是记录失败的步骤。请先用 go env GOFLAGS 查看当前的值。回想阅读材料中 -mod=mod 如何处理 vendor,就能理解这条消息。
在 GOPROXY=off 下用 vendor 构建
在 GOPROXY=off 下,仅用 vendor 构建,生成 /root/goair/bin/hello-vendor。
有一个 -mod 的值可以让它使用 vendor。请覆盖环境中的 GOFLAGS,或者直接在命令行中给出。即使模块缓存是空的,也必须能成功。
用 go.sum 编写导入记录
编写 /root/goair/intake.txt,把 go.sum 中模块 zip 的哈希行写成 모듈 버전 해시(占位符依次为模块、版本和哈希)的形式。每个哈希都必须与 /srv/goproxy 中的 .ziphash 相同。
go.sum 的行有模块、版本、h1: 哈希三栏。版本之后带有 /go.mod 的行是 go.mod 文件的哈希,与 zip 不同。请与代理目录中的 .ziphash 文件逐行核对。