ci中go build卡住超时主因是模块缓存未复用:go111module未显式设为on、go mod download未提前执行、$gopath/pkg/mod未持久化挂载,三者缺一不可;私有模块需goproxy配置,direct fallback。

CI 中构建超时,90% 不是网络慢,而是模块缓存没复用或根本没建起来——go mod download 没提前跑、GO111MODULE 没显式开、$GOPATH/pkg/mod 目录没持久化,三者任缺其一,就会在 go build 阶段卡住并超时。
为什么 CI 里 go build 会突然卡住等下载?
Go 工具链不会在 go build 时“顺手”补下载缺失模块;它发现某个 import 对应的模块不在本地缓存中,就直接报错退出(如 module github.com/some/pkg not found),或阻塞在 Fetching 阶段直到超时。这不是 bug,是设计行为。
-
go mod download必须作为独立步骤显式执行,且要在go test和go build之前 - 仅靠
go build -mod=readonly或-mod=vendor不能替代下载动作——前者拒绝修改go.mod,后者要求vendor/已存在 - GitHub Actions 的
actions/setup-go默认设了GO111MODULE=on,但 Jenkins/GitLab Runner 上往往仍是auto,尤其当系统装过 Go 1.10 或更早版本时
GO111MODULE=on 必须写死在脚本开头
别信文档说“1.16+ 默认开启”,CI runner 是干净容器,go env 输出里 GO111MODULE 很可能为空或 auto,一旦当前目录外有 GOPATH 下的老项目,auto 就会退化成 GOPATH 模式,导致 go.mod 被忽略。
- 所有 shell 步骤第一行加:
export GO111MODULE=on - 如果用
make或自定义 wrapper 脚本,也要在里面重复 export,别只依赖环境变量继承 - 验证方式:
go env GO111MODULE输出必须是on,不是空或auto
缓存目录必须挂载且不被清理
$GOPATH/pkg/mod 是模块缓存主路径,但它默认落在 $HOME/go/pkg/mod,而多数 CI runner 的 $HOME 是临时目录,每次 job 结束即销毁。不挂载 = 每次从零下载。
- GitHub Actions:用
actions/cache@v4缓存$HOME/go/pkg/mod,key 建议含go-${{ hashFiles('**/go.sum') }},比单纯用 Go 版本更精准 - Jenkins:在
sh步骤前用ws指定固定工作区,并确保GOENV指向该路径下的.goenv,避免go env -w写进容器临时$HOME - 禁止在 CI 脚本里出现
go clean -modcache—— 它清的是开发者本地磁盘,对 CI 无意义,反而强制重下
私有模块 + 代理配置容易漏掉 direct
设了 GO111MODULE=on 和 go mod download,但私有模块(如 git.internal.company/project)仍 404,大概率是 GOPROXY 缺少 fallback。
- 错误写法:
export GOPROXY=https://goproxy.cn→ 所有请求都发给镜像站,私有域名被拒 - 正确写法:
export GOPROXY=https://goproxy.cn,direct→ 镜像站查不到就自己连 Git 服务器 - 若用 Nexus/Athens 私有代理,也得加
,direct在末尾,否则内网 GitLab 地址全走不通 - 验证:
go list -m private.module@latest应成功返回版本,而不是not found
最常被跳过的一步是:没确认 go mod download 是否真跑完了。加 -v 参数看输出,最后一行不是 “done” 而是卡在某个 curl,说明代理或 DNS 还有问题——这时候再查 GO111MODULE 或缓存挂载,已经晚了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











