离线go环境必须预拉取全部依赖至$gomodcache并确保gopath路径一致,同时设goproxy=off和gosumdb=off;vendor方案可绕过路径依赖但需手动处理replace模块及启用-mod=vendor。

离线包缓冲区不是“配置出来”的,而是预拉取+路径复用
Go 没有类似 npm install --cache 那样运行时动态指定本地缓存目录的开关。所谓“本地离线包缓冲区”,本质是复用 Go 工具链已有的模块缓存目录 $GOMODCACHE(默认为 $GOPATH/pkg/mod/cache/download/),关键在于提前把所有依赖完整落到这个路径下,并确保离线机的 GOPATH 和 GOMODCACHE 路径与联网机完全一致。
常见错误现象:在离线机执行 go mod download 报 proxy.golang.org: no such host 或卡住——这不是缓存没配好,而是 Go 还在试图联网,根本没走到本地读取逻辑。
- 必须在联网机器上,用**目标环境完全相同的 Go 版本**(如
go1.22.3)执行go mod tidy→go mod download -x - 运行
go env GOMODCACHE确认真实路径,然后打包整个该目录(不是$GOPATH/pkg/mod软链接,是实际存放 .zip/.info 的物理路径) - 离线机解压后,必须保证
go env GOPATH输出和联网机一致;否则$GOMODCACHE会指向错误位置,Go 找不到包 - 不要手动改
GOMODCACHE环境变量——Go 1.13+ 会自动推导,硬设反而容易出错
为什么 GOPROXY=off + GOSUMDB=off 是硬性前提
只设 GOPROXY=off 不够。Go 在构建时仍会尝试连接 sum.golang.org 校验 go.sum,局域网或离线环境下这一步必然失败,报错如 verifying github.com/xxx@v1.2.3: checksum mismatch 或直接 timeout。
必须同时关闭两个开关:
-
go env -w GOPROXY=off:禁用所有代理,强制只查本地$GOMODCACHE -
go env -w GOSUMDB=off:跳过校验步骤(注意:这意味着你完全信任自己打包的缓存内容) - 验证是否生效:
go env GOPROXY GOSUMDB应输出off off - 别用
GOSUMDB=""—— 空字符串会被 fallback 到默认值,依然联网
vendor/ 不等于离线缓冲区,但它能绕过 $GOMODCACHE 路径依赖
如果你无法控制离线机的 GOPATH 路径(比如 CI 环境或容器中路径不固定),go mod vendor 是更鲁棒的离线方案:它把所有依赖复制进项目根目录的 vendor/ 文件夹,构建时不再依赖全局 $GOMODCACHE。
但要注意几个坑:
- 执行前必须先
go mod tidy,否则vendor/modules.txt会漏掉间接依赖 -
go mod vendor不处理replace到本地路径的模块,这些得手动拷贝并确保 import 路径匹配 - 构建时需加
-mod=vendor参数:go build -mod=vendor,否则 Go 仍优先走go.mod和pkg/mod - vendor 后仍要关
GOSUMDB=off,因为 Go 默认仍会校验go.sum中的哈希值
交叉编译时 cgo 依赖的缓冲区陷阱
如果项目含 cgo(比如用到 net 包的 DNS 解析、SQLite 绑定等),光打包 Go 模块不够。离线机还需安装对应平台的 C 工具链(gcc、pkg-config)和系统库头文件(如 libc6-dev、libssl-dev)。
这类依赖不会出现在 $GOMODCACHE 里,也无法被 go mod vendor 捕获:
- 在目标离线系统上运行
go list -c '{{.CgoPkgConfig}}' std查看是否启用 pkg-config - 若用
CGO_ENABLED=1交叉编译,需提前在目标系统部署对应架构的sysroot和头文件,不能靠 Go 模块机制解决 - 国产 OS(如麒麟、统信)常需额外适配,比如替换
openssl为国密库,这时连 Go 模块都得 fork 修改
真正麻烦的从来不是 Go 模块本身,而是那些藏在 cgo 背后、必须由操作系统提供的底层绑定。离线环境里,它们比 go.sum 更难打包,也更容易被忽略。











