docker中go模块依赖不缓存的根源在于dockerfile指令顺序错误:必须先copy go.mod和go.sum再run go mod download,否则代码变更会破坏前置层缓存,导致依赖重复下载;正确顺序可确保仅当依赖文件变化时才重新下载。

Go模块依赖在Docker里不缓存,每次构建都重下,不是网络慢,是Dockerfile写法错了。
go mod download 必须在 COPY 代码之前执行
这是最常踩的坑:把 COPY . . 放在 go mod download 前面,导致每次改一行代码,Docker 就清掉前面所有层——go.mod 和 go.sum 虽然没变,但因为上层变动,缓存失效,go mod download 只能重跑。
- 正确顺序:先
COPY go.mod go.sum ./,再RUN go mod download,最后COPY . . - 如果项目用私有模块,记得提前设置
GOPRIVATE=git.example.com/*,否则go mod download会卡在校验环节 -
go mod download下载的是go.sum锁定的精确版本,不触发go mod tidy,更稳定
多阶段构建中依赖缓存只保留在 builder 阶段
builder 阶段的 /go/pkg/mod 缓存不会自动传给 runtime 阶段——也不该传。runtime 阶段不需要任何 Go 工具链,只运行二进制文件。
- builder 阶段的
go mod download结果会被完整缓存,只要go.mod和go.sum不变,后续构建就跳过下载 - 不要在 runtime 阶段尝试
go mod相关命令,scratch 或 alpine 镜像里根本没go命令 - 如果要用
vendor目录固化依赖,需在 builder 阶段RUN go mod vendor,然后COPY vendor ./vendor,但会增大构建上下文体积
GOPROXY 和 GOSUMDB 必须显式配置
CI/CD 环境或内网构建时,不设代理会导致 go mod download 超时失败,错误信息通常是:Get "https://proxy.golang.org/...": dial tcp: i/o timeout。
- 推荐写法:
ENV GOPROXY=https://goproxy.cn,direct GOPROXY=https://proxy.golang.org,direct(双备选,防单点故障) - 校验开关必须配:
ENV GOSUMDB=sum.golang.org,禁用则加ENV GOSUMDB=off(仅限可信离线环境) - 若用企业私有代理,确保它支持
/@v/vX.Y.Z.info和/@v/vX.Y.Z.mod接口,否则go mod download会 404
CGO_ENABLED=0 影响依赖是否可静态链接
启用 cgo 会让某些模块(比如 net、os/user)动态链接系统库,导致二进制无法在 scratch 或 distroless 镜像里运行,报错类似:standard_init_linux.go:228: exec user process caused: no such file or directory。
- 绝大多数 Web 服务应设
CGO_ENABLED=0,强制静态链接,兼容性更好 - 若必须用 cgo(如调用 C 库),runtime 阶段不能用
scratch,得选alpine或debian:slim,并安装对应头文件和共享库 -
CGO_ENABLED=0不影响go mod download行为,但会影响最终二进制对系统库的依赖
真正卡住构建速度的,往往不是网络,而是缓存没命中;真正让镜像跑不起来的,也常常不是代码,而是 CGO_ENABLED 和基础镜像不匹配。这些点不手动验证一遍,光看文档容易漏掉。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











