离线go构建真正可行的路径是在有网且go版本完全一致的机器上预拉取全部依赖并固化校验,再将缓存目录、goproxy=direct、gosumdb=off配置及环境变量一并迁移至离线机;go mod download在离线机执行必失败,因默认强依赖proxy.golang.org和sum.golang.org。

离线物理机上能跑 go build 不等于真离线——只要 go mod download、校验或模块解析阶段发起一次 DNS 查询,构建就算失败。唯一可靠路径是:在有网机器用**完全一致的 Go 版本**预拉取全部依赖并固化校验,再把缓存 + 环境配置一并搬过去。
go mod download 必须在联网机执行,且不能带任何动态参数
离线机上运行 go mod download 会直接报 proxy.golang.org: no such host 或卡在 verifying 阶段。这不是超时问题,而是 Go 默认强制联网查 proxy 和 sumdb。
- 在联网机上,用和目标离线机**完全相同的 Go 版本**(如
go1.22.5)执行:go mod download -x,加-x可看到每个模块实际落盘路径,便于核对完整性 - 严禁使用
-u、@latest、@master等触发远程查询的参数;也不要用go get替代,它隐含更新行为 - 若项目含
replace指向私有 Git 地址(如git.internal.company/mylib),必须先git clone到本地,再用go mod edit -replace=git.internal.company/mylib=./mylib绑定为相对路径
GOPROXY=direct 和 GOSUMDB=off 缺一不可
只设 GOPROXY=direct 不够——Go 仍会尝试连接 sum.golang.org 做哈希校验,报错类似 checksum mismatch 或 failed to load hash from sum.golang.org。
- 离线机必须执行:
go env -w GOPROXY=direct(注意不是""或off) - 同时执行:
go env -w GOSUMDB=off(设为off才真正跳过校验;设为空字符串仍可能 fallback 到默认值) - 验证是否生效:
go env GOPROXY GOSUMDB输出应为direct和off - 不要用
export GOPROXY=direct临时设置——子进程(如 CI runner、systemd service)可能不继承,必须用go env -w写入配置文件
缓存目录结构不能扁平化,$GOPATH/pkg/mod 必须整棵拷贝
Go 的模块缓存不是简单 ZIP 解压就能用。它依赖严格的目录结构:$GOPATH/pkg/mod/cache/download/ 存原始 zip,$GOPATH/pkg/mod/github.com/xxx/yyy@v1.2.3 是解压后源码,两者缺一不可。
- 打包时保留完整路径:
tar -czf mod-cache.tgz $GOPATH/pkg/mod,不是只打cache/或modules.txt - 解压到离线机对应位置:确保
$GOPATH已正确定义(如/home/user/go),然后tar -xzf mod-cache.tgz -C /home/user/go - 别信
go list -m all显示“全了”就完事——要真正跑一次go build -x(加-x查看是否发出任何connect系统调用) - 如果项目用了
go mod vendor,也得同步拷贝vendor/目录,但注意:vendor 不包含间接依赖(// indirect),所以仍需完整pkg/mod缓存
交叉编译或启用 CGO 时,libc 和头文件必须提前验证
离线构建 ARM64 二进制却在 x86_64 机器上跑通,不代表部署成功。CGO_ENABLED=1 时生成的二进制会动态链接宿主机 libc,目标机缺少对应 .so 就报 not found。
- 禁用 CGO:
CGO_ENABLED=0 go build,但注意net包 DNS 解析会失效(纯 Go 实现不读/etc/resolv.conf) - 启用 CGO 时,离线机必须已安装对应开发包:Ubuntu/Debian 上是
libc6-dev,CentOS/RHEL 是glibc-devel,还要有pkg-config - 检查哪些包含 CGO:
go list -f '{{.CgoFiles}}' ./...,对关键依赖(如github.com/mattn/go-sqlite3)提前静态编译并replace进来 - 用
file your-binary看是否含interpreter /lib64/ld-linux-x86-64.so.2;用ldd your-binary确认所有依赖库在目标机存在
最易被忽略的是环境变量写入位置和子进程可见性——/etc/profile.d/golang.sh 必须存在且被所有 shell 类型加载,否则 go env GOROOT 在 Jenkins 或 systemd 里输出为空;还有 go.sum 文件末尾的空格或 Windows 换行符,会导致 checksum mismatch 却查不出原因。











