GO111MODULE=on是硬性前提,auto模式在私有路径下会静默退回到GOPATH导致module not found;必须显式设置并配合GOPRIVATE与GOPROXY配对使用,且go.mod模块路径须与Git URL严格一致。

GO111MODULE=on 是硬性前提,auto 模式在私有路径下会静默退回到 GOPATH
私有化集群里一旦遇到 go mod download 失败、拉到错误版本、甚至根本找不到模块,八成是 GO111MODULE 没设对。默认的 auto 模式会在当前目录没 go.mod 时回退,而私有仓库路径(比如 git.internal.company.com/team/lib)往往不满足“在 GOPATH/src 下有对应目录”这个旧规,结果就是 silent fallback + 报错 module not found。
必须显式设为 on:
-
export GO111MODULE=on(Linux/macOS)或set GO111MODULE=on(Windows) - 不能依赖 shell 启动脚本或 CI 配置里的“默认值”,每个构建环境都得单独确认
- CI/CD 流水线中建议在
go build前加一行go env -w GO111MODULE=on,避免被继承环境覆盖
GOPRIVATE 和 GOPROXY 必须配对使用,否则私有模块走代理就 404
GOPRIVATE 告诉 Go:“这些域名下的模块跳过代理和校验”,但光设它不够——如果 GOPROXY 还是 https://proxy.golang.org,Go 仍会先发请求过去,而公有代理显然无法解析内网地址,直接返回 404 或 timeout。
正确做法是:
立即学习“go语言免费学习笔记(深入)”;
-
export GOPRIVATE="git.internal.company.com,*.company.com"(支持通配符,但不支持二级泛匹配如*.git.*) -
export GOPROXY="http://athens.internal:3000,direct":优先走内网 Athens 代理,失败再 fallback 到direct(即直连 Git) - 绝对不要设
GOPROXY=direct单独使用——虽然能绕过代理,但会失去缓存、并发拉取慢、且无法统一审计依赖来源
go.mod 中模块路径必须与 Git URL 完全可映射,别指望 replace 或 alias 替代
常见错误是把仓库放在 https://git.internal.company.com/team/utils,却在 go.mod 里写 module myutils 或 module internal/utils。Go 不做路径重写,go get 会尝试访问 https://proxy.golang.org/myutils/@v/list,必然失败。
必须严格对齐:
- Git HTTPS 地址是
https://git.internal.company.com/team/utils→go.mod第一行必须是module git.internal.company.com/team/utils - 用 SSH?确保
~/.gitconfig有[url "git@git.internal.company.com:"] insteadOf = https://git.internal.company.com/,否则go默认走 HTTPS 协议并认证失败 -
replace只用于本地开发调试,集群部署时应删掉——它会让go mod vendor或go build仍需访问原始 Git 地址来校验 checksum
内网无公网出口时,vendor 目录不是银弹,得配合 GOPROXY=direct + GOPRIVATE
有人觉得 “go mod vendor 一把梭,把所有依赖打进项目目录就万事大吉”,但在私有集群里这招容易翻车:vendor 只包含直接依赖,间接依赖(// indirect)可能漏掉;更麻烦的是,go build 仍会读 go.sum 并尝试校验远程模块——若 GOPROXY 没切到 direct,照样卡住。
稳妥做法是:
- 先设
GOPROXY=direct和GOPRIVATE,再运行go mod vendor - 检查生成的
vendor/modules.txt是否包含所有// indirect项(可通过go list -m all | grep -v '^\(github\|golang\.org\)' | wc -l对比) - CI 构建阶段加校验:
go mod verify必须成功,否则说明 vendor 不完整或 checksum 不匹配
真正麻烦的从来不是命令怎么敲,而是 Git 地址、go.mod 路径、GOPRIVATE 域名、代理配置这四者之间差一个字符就全崩——每次部署前花 30 秒用 go list -m all 看一眼实际解析出的模块路径,比事后 debug 两小时强得多。


















