在内网配置 Golang 开发环境容易踩很多坑,有时踩到怀疑人生。
想从本质聊下坑源自何处,更清晰的定位思路。
若有错,请告诉一声。
不聊细节,不聊包版本号的机制。也不聊包管理器的各个方面,话题太大。
[TOC]
包管理器可减轻我们对依赖外部代码的管理负担,是个好东西。
包管理器的职责可能包括(但不限于):
- 版本号形式?
- 如何发布依赖包?
- 依赖包的下载方式?
- 如何防止依赖包内容篡改?
- 如何处理依赖包版本间兼容关系?
- 等等很多 ......
历史:Golang 的包管理器发展过程坎坷,从最开始的无包管理器,到第三方包管理器百花齐放,到现在(2021 年)尘埃落定为 Go Modules 方案 。
疑惑:历时多年确定下来的 Go Module 按理说用起来应该很丝滑才对,为何开发者配置开发环境时依然会踩那么多坑?(特别是公司内网中)
Golang 为了做得更好,采取了以下两个原则(但不限于):
- 去中心化
- 安全
上述两个原则,个人认为是引发 Go Module 内网配置环境时各种坑的主要诱发原因。
去中心化:无需将依赖包发布到 某个网站,可直接从源码网站(如 GitHub)获取依赖包。
GOPROXY 不算中心化,因为没有 GOPROXY 依然能正常运作
- 坑:依赖 Git
- 若想直接从源码网站下载依赖包,需安装对应的 VCS 工具
- Git 命令不成功,会导致依赖包下载不成功,即 Git 本身的所有坑,也会成为 Go Module 使用过程中的坑
- Git 可能的坑很多,包括但不限于:
- 若走 HTTPS,则需输入用户名密码
- 若走 SSH,则需预先配置 SSH 公钥私钥
- 若是内网、远程环境,可能还得为 HTTPS、SSH 配置各自的代理
- Git 自身版本不能太低
- 等等还有很多 ......
- Git 可能的坑很多,包括但不限于:
什么是不安全:
- 下载时内容被篡改
- 不小心自动升级到了有 bug 的依赖包版本
安全:就是能避免上述问题
- 引入 GOSUMDB 机制
- 类似区块链的 校验机制,使得依赖包内容一旦被篡改,必然能被发现
- 引入 GOPROXY 机制
- 可避免因源码网站依赖包若被删导致项目不可构建,因为 GOPROXY 会缓存依赖包
- 引入 基于语义的版本号 和 最小版本选择 机制
- 默认不自动升级依赖包版本,避免因自动升级带来的不确定性
- GOSUMDB 中的模块只能是公开模块,不能是公司内网的模块
- 因为 GOSUMDB 必须实现 lookup 接口 ,此接口必然会泄露内网模块的 import path
- 坑:有内网模块时,必须通过 GOPRIVATE(或 GOSUMDB=off) 区分公共模块和内网非公开模块
- 这就增加了用户的心智负担,且初用者大概率会忘记配置
- GOPROXY 相关的坑
- 同样需通过 GOPRIVATE 或(或 GOPROXY=direct)来区分公共模块和内网模块
- 因为公网用户不能通过官方 GOPROXY 获取到内网依赖包
- 初用者容易将 GOPROXY 与 https_proxy 误解为同样功能的东西(实质是完全不同的概念)
- 同样需通过 GOPRIVATE 或(或 GOPROXY=direct)来区分公共模块和内网模块
下图的任何一个环节出错,都可能会导致 Go 下载或校验依赖包失败。
出错时,错误信息不足,例如:
git ... reading ... at revision ... : unknown revision ...
:- 多数情况时因为 git 下载依赖包失败,开发者可能不知道下载依赖包时用到了 git,即使知道是 git 但不知道 git 的哪个配置有问题,开发者只能四处搜填坑方案
invalid version: git fetch -f origin refs/heads/*:refs/
:- 经常情况缓存重试就行
go clean -x --modcache
,但是什么原因导致的错误?未知
- 经常情况缓存重试就行
- 有些公司内网需配置 HTTP 代理才能访问公网
- Golang 与 HTTP 代理的关系
- Golang 获取 go-import :基于 HTTPS GET
- 从 GOPROXY 获取依赖包基于:HTTPS GET
- 从 GOSUMDB 获取校验信息基于:HTTPS GET
- 所以,https_proxy、no_proxy 没配置或配置不正确,都会导致上述 3 种情况失败
- 若内网有些环境需代理、有些环境不需代理,问题更复杂了
- Golang 与 HTTP 代理的关系
- 有些公司内网域名不是公网域名
- 不是公网域名,会导致浏览器无法 验证 HTTPS 证书,从而导致出现类似
x509
的错误- 此时需安装内网对应网站 HTTPS 对应的证书
- Mac 中安装证书需管理员权限、有时证书会自动变不信任需重新信任
- 此时需安装内网对应网站 HTTPS 对应的证书
- 不是公网域名,会导致浏览器无法 验证 HTTPS 证书,从而导致出现类似
可以有,但可能不完美,甚至可能带来额外的问题。
- 因为涉及的方面较多:Git 的各种配置、HTTPS 证书的安装和权限、内网环境的判断、环境变量配置、GoLand、Win 和 Mac
- 修改各种配置文件可能会与开发者自行的配置冲突
- SSH 公钥粘贴到源码网站,这步貌似无法通过简单工具实现
- 即使是内网,可能也有不同的环境,有些需代理、有些无需代理
假设内网搭建了 GOPROXY、GOSUMDB 服务,且采用的是公网域名,能否彻底让各位 Gopher 少踩各种坑?
- 能解决的问题:
- 增加对内网公开(但公网不公开)模块的:
- SUMDB 校验,提高了安全性,防止内网模块被篡改
- 依赖包内容缓存,以免内网源码网站对应依赖包版本被删导致项目不能构建
- 公司内部开发人员配置不当造成 import path 泄露到公网
- 缓存热点代码依赖,可降低公司公网出口带宽
- 增加对内网公开(但公网不公开)模块的:
- 不能解决的问题:
- 内网的私有依赖包(即使在内网,也仅部分人有权限的依赖包)
- 此时前面所说的所有坑,都依然避免不了,因为私有包都不能经过 GOPROXY、GOSUMDB,且只能通过 Git 直接获取源码
- 内网的私有依赖包(即使在内网,也仅部分人有权限的依赖包)
总的来说:
- 若处于内网,且所有项目代码都是内网公开的,则内网的 GOPROXY、GOSUMDB 几乎解决所有问题
- 若内网中依然有非公开的项目源码,则该踩的坑一个都不会少
- 笔者依然会选择官方默认的 GOPROXY、GOSUMDB(
proxy.golang.org
、sum.golang.org
)、自行安装 HTTPS 证书、自行配置 HTTP 代理、自行配置 SSH Key
- 笔者依然会选择官方默认的 GOPROXY、GOSUMDB(
包管理器 去中心化
、安全
都是 Golang 包管理机制的目的之一,GOPROXY、GOSUMDB 都是合理的存在。只是在达到这个目的的过程中,会附带一些条件和约束,例如:
- 源码网站即使是内网网站,也应采用公网域名
- 本来就要区分内网依赖包、公网依赖包,只是其他包管理器是通过搭建内网镜像源,Go 是通过环境变量 GOPRIVATE 来区分
- 内网访问外网应尽量无需配置 HTTP 代理,应对内网用户尽量透明无感知
- 对 Git 的依赖本就是开发者的开发环境的基本要求
很多坑来自于内网环境本身的不合理、来自于开发者自己电脑的开发环境不完善。这些不合理,本就不应存在,与 Golang 无关。
踩好这几样抗,一般问题不大,出问题时也是按排除法逐项排查:
- HTTPS 代理
- HTTPS 证书
- GOPRIVATE
- Git clone
Go Module 只是在促成更好的包管理器时,暴露了包管理器之外的环境的不合理之处。当然 Go 自身的出错提示信息不足,也是一大因素。