根本原因是go模块缓存目录被设为只读,导致go mod download写入/gopkg/mod/cache失败;应通过export gopath=$home/go和gomodcache=$home/go/pkg/mod重定向缓存路径并创建目录。

go mod download 报错 permission denied 在 /go/pkg/mod/cache
根本原因是 Go 的模块缓存目录被系统或容器环境设为只读,go mod download 或 go build 尝试写入 /go/pkg/mod/cache 时失败,典型错误信息是:permission denied 或 operation not permitted。
这不是模块本身的问题,而是 Go 工具链在默认路径下没有写权限。常见于 Docker 容器(比如用了 readonly: true 挂载)、CI 环境(如 GitHub Actions 的某些 runner)、或 macOS 上启用了 SIP 后误改了系统目录权限。
- 先确认当前缓存路径:
go env GOPATH和go env GOCACHE,但真正关键的是go env GOMODCACHE—— 这才是模块下载存放位置 - 不要手动 chown 或 chmod 系统级
/go/pkg/mod目录,尤其在容器里可能被覆盖或引发更隐蔽的权限冲突 - 最稳妥的方式是把模块缓存移到用户可写路径,比如
$HOME/go/pkg/mod
用 GOPATH + GOMODCACHE 重定向模块缓存位置
Go 不强制要求使用 GOPATH,但通过它能自然接管 GOMODCACHE 默认值($GOPATH/pkg/mod)。只要确保 $GOPATH 可写,整个模块缓存链就通了。
执行以下命令设置(以 Bash/Zsh 为例):
export GOPATH=$HOME/go export GOMODCACHE=$HOME/go/pkg/mod mkdir -p $GOMODCACHE
之后再运行 go mod download 就会写入 $HOME/go/pkg/mod,不再碰系统保护路径。
- 如果已在 CI 或容器中使用
go build,建议在构建脚本开头就 export 这两个变量,而不是依赖基础镜像的默认值 - 注意:设置
GOMODCACHE后,GOPATH不再影响编译输出(go build输出仍由-o控制),但它决定了模块缓存根路径 - 某些旧版 Go(GOMODCACHE,必须升级到 Go 1.13+ 才支持该环境变量
容器内运行时避免挂载只读 /go
Docker 中若用 FROM golang:alpine 或类似镜像,默认 /go 是可写的;但如果在 docker run 时加了 --read-only,或通过 volume 挂载了只读宿主机路径到 /go,就会触发该问题。
- 检查是否无意挂载了只读卷:
docker inspect <container> | grep -A5 Mounts</container>,看ReadOnly字段是否为true - 若必须使用只读根文件系统(如安全加固场景),请显式将
/go/pkg/mod单独作为 tmpfs 挂载:--tmpfs /go/pkg/mod:rw,size=100m - 不要用
chown -R在 ENTRYPOINT 里修复权限 —— 多阶段构建中,上一阶段的/go在下一阶段可能已不可写,且容易掩盖真实配置问题
go mod vendor 无法绕过写缓存的误解
有人以为启用 go mod vendor 就能完全脱离网络和模块缓存,其实不然:go mod vendor 本身仍需先拉取模块到 GOMODCACHE,再复制进 vendor/ 目录。如果缓存路径不可写,vendor 命令照样失败。
- 验证方式:删掉本地
vendor/,执行go mod vendor -v,观察日志里是否卡在downloading阶段 - 正确做法是先解决缓存路径写权限,再执行
go mod vendor;或者直接用go mod download -x看具体哪一步报错 - 如果目标是离线构建,应提前在有网环境完成
go mod download+go mod vendor,然后把整个项目(含vendor/)打包带走,而非指望某条命令跳过缓存
模块缓存路径的写权限不是“可选优化”,而是 Go 模块机制的执行前提。一旦环境限制了默认路径,就必须显式重定向,不能靠临时 chmod 或忽略错误来蒙混过关。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











