不一样的go语言-athens私仓安装

前言本系列文章曾多次提及go的依赖管理,提到了私仓,构件系统等概念,也曾提及当前流行的go构件系统,如athens,jfrogartifactory。鉴于jfrog的收费特性,本文只选择athens着重介绍。包括安装、使用、踩坑、源码分析等。简要介绍在依赖管理方面,go相较于其他语言,其提供了从开放的源码仓库(github、bitbucket等)动态获取源码的工具,最早是goget,go1.11后...

不一样的go语言-athens私仓安装

前言

  本系列文章曾多次提及go的依赖管理,提到了私仓,构件系统等概念,也曾提及当前流行的go构件系统,如athens,jfrog artifactory。鉴于jfrog的收费特性,本文只选择athens着重介绍。包括安装、使用、踩坑、源码分析等。

简要介绍

  在依赖管理方面,go相较于其他语言,其提供了从开放的源码仓库(github、bitbucket等)动态获取源码的工具,最早是go get,go1.11后又新增了go mod。而像java,其本身并没有提供类似的命令,因而才诞生了maven、gradle这样的构建系统。它们的构件则来源于公共仓库或者自行搭建的私有仓库。go的创造者估计是想回避掉这些问题,而直接由官方来提供,这样更便利于开发人员。但其短板则在于私仓,因为私仓在网络、权限、安全等方面会有诸多的限制,并不能像github那样公开,在这样的情况下,go get或者go mod也只能是心有由而力不足。鉴于此,go提出了GOPROXY的概念,通过vgo download protocol协商软件包的获取。剩下的网络、权限等问题就交由proxy server来解决了。

go软件包协议

Defining Go Modules,协议的开头,Russ Cox就指明了go modules的设计目标,只要包括以下六点:

  1. 希望约定以tag的方式发布软件包,同时又能支持获取指定commit的软件包;
  2. 希望不借助其他版本管理工具为实现软件包的获取;
  3. 希望支持软件包的多版本管理;
  4. 希望在获取软件包时拥有前置个人或公司的代理仓库或私有仓库的能力;
  5. 希望支持在未来扩展实现公有仓库,同时又能在没有公有仓库的情况下正常运作;
  6. 希望废弃vendor文件夹。

协议的主体内容主要包括:

内容描述
软件包版本遵循语义版本2.0(Semantic Versioning)同时支持tag与commit方式
go modgo.mod定义go.mod文件的内容
软件包定义软件包在源码库的组织方式支持分支方式、子目录方
发布方式定义软件包的发布方式软件包仓库需支持go-get=1参数获取软件包meta
打包方式定义软件包的打包方式在构件系统中以zip格式保存
下载协议定义软件包如何从构件系统获取实现四个或六个http请求接口
代理服务定义GOPROXY服务系统的概念如goproxy.io, gocenter.io

download protocol约定以下四个http请求接口:

  1. GET baseURL/module/@v/list: 获取指定软件包的所有已知版本信息,每个版本一行。
  2. GET baseURL/module/@v/version.info: 获取指定软件包特定版本的json格式元数据。
  3. GET baseURL/module/@v/version.mod: 获取指定软件包特定版本的mod文件。
  4. GET baseURL/module/@v/version.zip: 获取指定软件包特定版本的zip源码包。

其中version.info响应定义如下:

type RevInfo struct { Version string // version string Name string // complete ID in underlying repository Shortstring // shortened ID, for use in pseudo-version Time time.Time // commit time}

以下两个请求为可选实现:

  1. GET baseURL/module/@t/yyyymmddhhmmss:获取与指定时间戳最近的一个版本,响应数据与version.json接口一致
  2. GET baseURL/module/@t/yyyymmddhhmmss/branch: 获取指定分支下,与指定时间戳最近的一个版本,响应数据与version.json接口一致。

athens私仓搭建

  依前文所述,go的构件系统其实是由两部分组成的,一是实现了vgo download protocol的服务;二是软件包仓库。前者是纯代理模式,比如goproyx.io,gocenter.io,其本身并不存储软件包,而只是转发请求从指定仓库(github等)获取所需软件包。后者真的就只是一个软件包仓库(如github,github目前并不是GOPROXY,虽然它可以是)。而athens则既是代理又是软件包仓库(类似于nexus,属于本地缓存仓,原始软件包仍然在公共仓库或私有仓库)。接下来的篇幅,着重于介绍如何安装并使用athens。

  athens本身使用go语言编写,除了通过常规运行方式之外,还支持docker、k8s的方式运行,本文介绍的方式为第一种。常规的运行方式遇到问题或者踩到深坑,可较快速找到问题所在,不需要再去考虑装载容器的因素。

  系统与网络环境说明:

说明
操作系统linux, centos 7
gitlab内网ip, 192.168.197.26,http端口10080,ssh端口10022,域名git.example.com
athens宿主机内网ip, 192.168.197.205
gogo 1.12
git clientgit-bash

  前方高能预警,为避免不必要的踩坑行为,特提醒如下。

  1. 务必为gitlab配置域名
  2. 务必使用https

以上两点,已经可以避免ip、域名、端口诸多烦人的问题。比如go get指令是不支持这样的指令的:

[eventer@localhost]# go get github.com:8080/gomods/athensgo get github.com:8080/gomods/athens: malformed module path “github.com:8080/gomods/athens“: invalid char ':'

  当然如果gitlab满足以上两点, 同时http与ssh端口又是默认80与443端口,那么athens体验过程应更为轻松。

安装步骤:

  1. 下载&编译athens
[eventer@localhost]# pwd[eventer@localhost]# /home/eventer[eventer@localhost]# git clone https://github.com/gomods/athens.git[eventer@localhost]# cd athens[eventer@localhost]# make build-ver VERSION=“0.2.0“
  1. 运行athens
[eventer@localhost]# pwd[eventer@localhost]# /home/eventer/athens[eventer@localhost]# ./athens -config_file=./config.dev.toml

  到这一步,默认配置的情况下,go的构件系统已经搭建好了,只需要将自己开发环境的go环境变量GOPROXY指向这里即可。IP地址:192.168.197.205:3000。其中192.168.197.205是athens安装机器ip。

  1. 修改默认配置

打开config.dev.toml,可能要修改的配置项说明如下。

配置项说明
Port端口号,默认3000
StorageTypememory, disk, mongo, gcp, minio, s3。本安装过程选择disk
FilterFile过滤策略,与GlobalEndpoint配合使用。
GlobalEndpoint全局代理,即athens的GOPROXY,可设置为https://goproxy.io
NETRCPath自动登录脚本,放在当前用户home目录下,文件名.netrc此处可用于访问git
GithubTokengithub访问令牌,用于访问github
HGRCPathMercurial自动登录脚本,放在当前用户home目录下,文件名.hgrc
Stogage->Storage.Disk当StorageType为disk时,需要修改此处

FileterFile

  athens约定的软件包过滤策略,当前可用策略包括D、-、 三种。D必须存在且放在第一行;-表示禁止下载此软件包,若请求,报403; 表示不从指定的GlobalEndpoint下载,而直接从域名指定的仓库获取软件包。-与 对软件包的策略可指定至版本,多个版本用,号分隔,甚至可使用版本修饰符(~, ^, >)。此外#开头的行表示注释,会被忽略。

D# 内网的gitlab不需要通过GlobalEndpoint下载  git.example.com  github.com/gomods/athens v0.1,v0.2,v0.4.1
修饰符说明
~~1.2.3表示激活所有大于等于3的patch版本,在语义化版本方案中,最后一位的3表示补丁版本。如1.2.3, 1.2.4, 1.2.5
^^1.2.3表示激活所有大于等于2的minor与大于等于3的patch版本。如1.2.3, 1.3.0
<<1.2.3表示激活所有小于1.2.3的版本。如1.2.2, 1.0.0, 0.1.1

  这个过滤策略主要用于API兼容或者软件包license改变时使用。

NETRCPath

  自动登录脚本,即遇到指定machine需要输入用户名密码时,则从登录脚本中寻找是否有匹配的配置项。示例如下:

# filename: .netrcmachine 192.168.197.26login eventerpassword 123456  
  1. gitlab访问配置

  前文已经讲述vgo download protocol,因此当athens接收到go get或go mod的指令时,需要做出正确的回应。这四个接口是依次执行下去的,后一个接口依赖于前一个接口的响应。而这其中的关键在于两个地方,其中一个是软件包仓库支持的获取元数据的接口(GET baseURL/module?go-get=1),第二个是获取软件包(GET baseURL/module/@v/version.zip)。当athens收到GET baseURL/module/@v/version.info指令时,如果本地没有,会直接调用go mod命令去指定的软件包仓库下载。而这个命令的第一步就是获取软件包元数据,即向软件包仓库发起请求GET baseURL/module?go-get=1,按照协议,软件包仓库应该返回如下类似响应:

<!DOCTYPE html><html><head><meta content='git.example.net/module git https://git.example.net/module.git' name='go-import'></head></html>

  之后go会使用git clone命令下载zip软件包至本地,至此go mod的使命完成。然后athens将软件包加上版本号,改名后放至本地仓库中,等待GET baseURL/module/@v/version.zip。

  可以看到关键的两步,第一步要返回准确的git地址,第二步要能访问git并clone下来。

  对于第一步,低版本的gitlab可能会返回不正确的meta,这里提供的方案是使用nginx来处理。方案如下(不同gitlab环境可能nginx的配置会有所不同,比如路径匹配):

if ($args ~* “^go-get=1“) {  set $condition goget;}if ($uri ~ ^/([a-zA-Z0-9_-] )/([a-zA-Z0-9_-] )) { set $condition “${condition}path“;}if ($condition = gogetpath) { return 200 “<!DOCTYPE html><html><head><meta content='git.example.net/$1 git http://git.example.net/$1.git' name='go-import'></head></html>“;}

  对于第二步,其实有两个方案可用,一是使用前文所说的.netrc文件,二是使用ssh。本文选择的是ssh。

  ssh方案要处理两件事情,一是go调用git clone命令,使用的是https协议,需要替换为ssh协议,这可以通过gitconfig文件完成,示例如下:

[eventer@localhost]# pwd[eventer@localhost]# /home/eventer[eventer@localhost]# touch .gitconfig

.gitconfing内容如下:

# filename: .gitconf
源文地址:http://www.guoxiongfei.cn/cntech/14841.html