介绍 Athens

欢迎来到 Athens,Gophers!我们在首页上给出了一个非常简洁的 Athens 概览,因此如果你想要了解更多,那么你就来对了地方!

本章将详细阐述 Athens 的功能,意义,以及如何在你的工作流中使用它。

下一步该去哪里

我们建议你从前往后阅读这个章节:

介绍 Athens 的子部分

Athens 101

什么是 Athens?

简而言之,Athens 是一个建立在 vgo(或 go1.11+) 之上的项目,通过它你可以更容易地处理包的依赖问题,即使在 VCS 无法访问的时候,你也可以重新构建你的项目。

Athens 的宏伟目标是提供一个用于存放依赖(而不是代码)的新地方。因为在 GitHub 上,每一份元数据都对应着唯一不变的代码块,所以 Athens 只需要控制原数据的存储就够了。

你可能已经知道“不可变”的意义,但请让我再次说明,因为这一点对整个系统是非常重要的。当小伙伴改变了他们的包,迭代,实验,或者其他的事情,代码在 Athens 中永远不会变。如果包的作者发布了一个新版本,Athens 会把它拉取下来,并展现出来。因此,如果你依赖包 M 的版本 v1.2.3,那么它在 Athens 中就永远不会改变。即使是强制推送或者是删除版本库,这都不会改变

下载协议

Athens 在 Go 命令行接口的基础上建立了一些端点,用来于外部提供模块的代理通信。我们称这些端点为_下载协议_

vgo 在下载协议上的原始调研报告可以在这里找到:https://research.swtch.com/vgo-module

每个端点都对应一个顶层模块。让我们假设模块 htp 是由 acidburn 编写的。

因此,我们下面提到的端点都假设位于 acidburn/htp/@v/{endpoint}(例如:acidburn/htp/@v/list

在下面的例子中,$HOST$PORT 都是 Athens 服务的主机和端口的占位符。

版本列表

这个端点返回 Athens 中模块 acidburn/htp 的版本列表。下面的列表由换行符分割:

GET $HOST:$PORT/github.com/acidburn/htp/@v/list
v0.1.0
v0.1.1
v1.0.0
v1.0.1
v1.2.0

版本信息

GET $HOST:$PORT/github.com/acidburn/htp/@v/v1.0.0.info

这会以 JSON 格式返回关于 v1.0.0 的信息。它看起来像:

{
    "Name": "v1.0.0",
    "Short": "v1.0.0",
    "Version": "v1.0.0",
    "Time": "1972-07-18T12:34:56Z"
}

文件 Go.mod

GET $HOST:$PORT/github.com/acidburn/htp/@v/v1.0.0.mod

这会返回文件 go.mod 的版本 v1.0.0.如果 $HOST:$PORT/github.com/acidburn/htp 的 v1.0.0 版本没有依赖, 那么响应就会像这样:

module github.com/acidburn/htp

模块源

GET $HOST:$PORT/github.com/acidburn/htp/@v/v1.0.0.zip

显而易见——它会把该模块的 v1.0.0 版本的源码以 zip 格式返回。

Latest

GET $HOST:$PORT/github.com/acidburn/htp/@latest

这个端点会返回对应模块的最新版本。如果没有 latest 标签,它会根据最后一次提交的哈希值去找到对应的版本。

为什么Athens重要?

不变性

Go社区的许多问题都是由于库(library)的消失或者在没有告警的情况下突然变化所引起的。上游的软件包维护人员很容易对他们的代码进行更改,但这可能会破坏您的代码,而大多数情况下这是一个意外! 如果您的软件使用的某个依赖项执行下列操作,该软件的构建是否会中断?

  • 提交(Commit) abdef 被删除了
  • 标签(Tag) v0.1.0 被强制推送(push)
  • 源码库被完全删除

由于应用程序的依赖项直接来自VCS(版本控制系统,如Github),因此上述情况都可能发生在您身上,并且当它们发生时,您的软件的构建过程可能会中断-哦,不! Athens通过将代码从VCS复制到_不可变_存储中来解决这些问题。

在这种方式下,您就不需要手动将任何内容上传到Athens后端存储。Go第一次向Athens请求依赖包时,Athens会从VCS(Github、Bitbucket等)获取。但一旦检索到该模块,它将永远保存在Athens的后端存储中,并且代理将不再返回到VCS中获取同一版本的依赖包。这就是雅典如何实现模块不变性。需要注意的是,后端存储掌握在您的手中。

逻辑

go命令行现在可以ping 您自己的服务器 来下载依赖项,这意味着您可以编写任何需要的逻辑来提供这种依赖项。包括访问控制(下面将讨论)、添加自定义版本、自定义分支和自定义包等。例如,Athens提供了一个验证钩子(hook),每个模块下载时都会调用它来确定是否应该下载此模块。因此,您可以用自己的逻辑扩展athens,比如扫描模块路径或代码以查找标红代码等。

性能

从Athens下载存储的依赖关系_显著_比从版本控制系统下载依赖更快。这是因为go get默认情况下使用VCS的下载模块,例如git clone。而go get启用GOPROXY时,将使用HTTP下载zip压缩包。因此,根据您的计算机和网络连接速度,从GitHub下载CockroachDB源代码zip文件只需要10秒,但git clone需要将近4分钟。

访问控制

比软件包消失更糟糕的是,软件包可能是恶意的。为了确保您的团队或公司不会安装此类恶意软件包,当go命令行请求一个被排除的模块(恶意软件)时,您可以让代理服务器返回500。这将导致构建失败,因为Go需要200 HTTP响应码。使用Athens,您可以通过过滤器(filter)文件实现此目的。

Vendor 目录成为可选

有了不变的、高性能和高鲁棒性的代理服务器,用户不再需要在每个库中都将vendor目录纳入其版本控制。go.sum文件确保在第一次安装之后不会处理任何包。此外,您的CI/CD在每次构建安装所有依赖项时都只需要很短的时间。

组件

从一个非常高的角度来看,系统中有三个主要的组件。

客户端

客户端必须是一个支持 module 的 go.编写该文档时,它是 Go v1.12+.

VCS

VCS 对 Athens 而言是一个外部源。Athens 扫描类似 github.com 等的多种 VCS,并获取源。

代理

我们部署在企业内部的代理主要是为了:

  • 托管私有模块
  • 排除对公有模块的访问
  • 存储公有模块

重点在于,这个代理并不打算成为上游代理的完整镜像。对于公有模块,它的角色是为了存储并提供访问控制。

Fork me on GitHub