RFC-0124 - 分散式产品集成:工件说明和传播

RFC-0124:分散式产品集成:工件说明和传播
状态已接受
领域
  • 常规
说明

一种用于描述和传播分散式产品集成工件的机制。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021-03-30
审核日期(年-月-日)2021-08-30

摘要

1

该机制包含两个基本方面:

  1. 使用适合于每个工件的兼容或理想版本和变体的元信息添加到要组装的产品的说明
  2. 传播工件,以便从来源和使用它们的集成代码库来识别、引用和访问工件。

设计初衷

分散式产品集成路线图文档中所述,需要在 Fuchsia 源代码树之外组装产品。为此,您需要在 Fuchsia 源代码树之外执行独立的映像组合工具,并为其提供必要的源代码或预构建工件。Fuchsia 源代码树提供 Zircon(Fuchsia 内核)和系统软件包及其他工件。各种 Peal 代码库会为其他组件(例如特定于产品的组件和运行程序)提供软件包。

Fuchsia 源代码树工件是定期生成的版本。同时,系统还会生成 Fuchsia SDK 的版本,这些版本由花瓣代码库定期导入,并进而在花瓣代码库的版本节奏中生成自己的 Fuchsia 工件。

总体来说,Palal 代码库的发布频率与 Fuchsia 源代码树的发布频率不一致,并且各版本的标识符也不同。花瓣可以选择将其版本标准与 Fuchsia 保持一致,例如为 Fuchsia SDK 的每个版本生成一个版本。

每个此类工件版本也可能会以不同的变体形式生成,例如,各种处理器架构的可执行文件、调试变体与优化变体的变体、由某些“稳定”标签和“最新”标签指定的变体(用于区分主干版本与稳定分支版本,或启用了或停用了构建时功能的变体)。

为了在独立于 Fuchsia 源代码树的集成代码库中组建此类工件的产品,这些工件必须可供集成代码库使用。此外,必须在工件的合适版本和变体中针对产品的每个版本和变体选择产品集成所需的工件。

当前的产品集成过程称为“全球集成”。通过一个称为“滚动”的过程,系统会将来自 Peal 代码库的预构建工件重新导入 Fuchsia 源代码树。然后,Fuchsia 产品会组合成来自最新源代码树下 Fuchsia 源代码树的所有工件的最终 build 产品,以及已到达集成代码库的已固定版本的 Peal 代码库中的预构建软件包。此过程如图 1 所示。

图 1 - 全球集成流程(图例 当前系统中所有协作部分的关系

此过程存在几个缺点:

  • 1
  • Fuchsia 系统的版本始终高于构建任何花瓣工件时使用的 Fuchsia SDK 版本,因为 Fuchsia 系统是根据 Fuchsia 源代码树的最新源代码修订版本构建的,但花瓣工件的 SDK 是根据早期修订版本构建的。
  • 如果来自不同花瓣的工件相互之间具有版本兼容性要求(例如,Flutter 运行程序和经过 Aot 编译的 Flutter 应用),则只能通过专门在同一滚轮中将它们滚动在一起来维护这些工件。
  • 即使某个花瓣工件在产品所有者的控制之下,用于产品集成的版本也不在产品集成之下,因为使新版本工件可用于产品集成的滚动流程会与所有其他滚轮对所有其他滚轮工件进行协调,并且可能会因任何其他产品的集成测试失败而被阻止。

提议的分散式产品集成流程在这些缺点的基础上进行了改进,这是在 Fuchsia 代码库之外进行产品组装的直接结果:

  • 产品组装配置保存在每个产品的单独集成代码库中,该集成代码库中可以由产品所有者控制。
  • 可以使用与 Fuchsia SDK 兼容的版本(在构建花瓣工件时)选择 Fuchsia 工件,以便在产品的所有工件之间实现 ABI 兼容性。例如,如果内容类似于 RFC-0002 中规定的 ABI 修订版本,并且对应于所需的 6 周 ABI 兼容性窗口,则由 Fuchsia 版本版本号的第一个组件表示,每当创建 Fuchsia 版本分支时都会递增该组件。因此,可以使一个产品中的所有工件与构建这些工件时所用 Fuchsia 发行版本号相同的第一版组件保持一致。
  • 您可以直接选择来自不同花瓣代码库的工件版本,以便它们满足相互兼容性要求,并且可以根据直接指定的限制条件推进到下一个版本,而无需为这对工件设置专用滚轮。例如,可以直接在相同 Flutter 和 Dart 发布版本号中选择 Flutter 应用和对应的 Flutter 运行程序。
  • 产品可以按照自己的发布节奏选择贡献的所有工件的版本和变体,而不会妨碍其他选择该版本的产品。

利益相关方

教员:abarth@google.com

审核者:aaronwood@google.com (Assembly)、etryzelaar@google.com (SWD)、wittrock@google.com (SWD)、atyfto@google.com (Fuchsia Build Infrastructure)、marvinpaul@google.com (TUF 服务器基础架构)、jsankey@google.com (RFC.google.com)、authora 和 en.google.com。

咨询:软件交付团队、代管式操作系统团队和基础架构团队成员。

社交:除了与咨询团队进行讨论之外,我们还将此 RFC 的草稿发送到了 FEC 讨论邮寄名单以供评论。

设计

在介绍设计概览之前,我们先介绍或阐明一些术语和概念。

术语

在以下段落中,粗体字词是其含义通过上下文解释的术语。

Fuchsia 源代码树包含多个不同的 Git 代码库,这些代码库由名为 jiri 的工具根据保存在名为 integration.git 的 Git 代码库中的配置一起配置到一个源代码树中。其中最重要的代码库是 fuchsia.git,但还有许多其他 git 代码库,包括第三方代码库。Jiri 配置还可控制是否将预构建工件加入源代码树的专用部分。预构建工件本身存储在名为 CIPD 的存储服务的修订版本控制下,而描述 CIPD 中预构建工件的位置和修订版本的 jiri 配置位于 integration.git 代码库中的 git 修订版本控制之下。

一个名为 Roller 的定期运行的构建作业尝试更新 Fuchsia 源代码树中包含的预构建工件的版本。如果可以使用更新后的工件版本构建和测试 Fuchsia 树的所有所需 build 产品,系统会提交对 Fuchsia 树的更改,而工件的更新版本现在为固定版本。不同的预构建工件可以有单独的滚轮。

在现状中,Fuchsia 源代码树同时充当 Fuchsia 产品中使用的许多工件的源代码库,以及集成仓库(其中每个 Fuchsia 产品由自己的部分组装而成)。

工艺品是指在组装商品时使用的任何原料。此类工件可从 Source Repositories 获取,可以直接作为源项之一获取,也可以作为通过执行代码库中的构建流程获得的构建产品。大多数此类工件是预构建的 Fuchsia 软件包,但它们还包含 Zircon(Fuchsia 内核),并且很快还可能包含子汇编规范文件。Zircon 内核和预构建软件包是预构建工件;子组件规范文件是一个源代码工件。

从一个源代码库获取的工件最终会发布到“工件存储区”。此类发布可以手动发布,也可以按计划自动发布。无论采用哪种方式,生成的工件都会发布到源代码库的专用工件存储区。您可以在任何能从源代码库外部找到工件的位置在 Artifact Store 中,无需引用源代码库,更不用说执行其构建流程。因此,工件存储区可以是 CIPD 目录、GCS 存储分区或 TUF 代码库。对于此处设计的流程,特定类型的工件存储区并非必需。

TUF 代码库用于向 Fuchsia 设备交付软件、向开发中的开发者 Fuchsia 设备或模拟器提供新重建的软件包,以及向生产中的 Fuchsia 设备提供 OTA 更新。基于内容地址存储服务在 Fuchsia 中使用 TUF 的具体方法特别适合存储 Fuchsia 软件包,而且由于许多工件都是 Fuchsia 软件包,因此在此设计中,倾向于将 TUF 代码库用作工件存储区。

属性是用于描述工件以便可以辨别其版本和变体的键值对属性。键描述的是可变性的维度,而值是工件所在的维度所在的位置。属性统一描述了工件的版本和变体。在大多数情况下,没有必要区分描述版本的属性与描述变体的属性。工件的发布者可以指定如下属性:

  • CPU 架构变体,x64arm64
  • debugoptimized 编译变体。
  • 构建工件时所用源代码库的提交版本。
  • 构建工件时使用的构建参数。
  • 构建工件时使用的 Fuchsia SDK 版本。
  • 已构建工件的语义版本。例如,Chromium 发布版本(如 M88.xxx)或 Cast 发布版本(如 1.56.xxx)。
  • 实现后,Fuchsia 系统工件的 RFC-0002 规定的 API 级别和 ABI 修订版本。
  • 由花瓣提供的 API 级别或 SDK 版本,不在 RFC-0002 的范围内,但与系统 ABI 一样重要。例如,构建 Flutter 应用时使用的 Flutter SDK 的发布版本。

传递属性:某些属性描述工件的传递属性,因为它们与构建工件时所基于的输入属性相关。例如,Fuchsia SDK 版本或 Flutter 版本实际上是用于构建所述工件的前体工件的属性。预计此类传递属性将进一步扩展。因此,允许以递归方式将属性值作为包含键值对的对象。

依赖项属性:工件的依赖项(包括其版本和变体)也可以表示为属性。但是,Fuchsia 软件包是封闭的,因此已包含其依赖项。因此,依赖项通常不会经常出现在 Fuchsia 工件的属性中。

现状

在当前的全局集成流程中(如图 2 所示),Palal 构建流程使用 CIPD 目录作为其工件存储区。工件存储区将工件保留在路径名称(在 CIPD 中称为“软件包”)下,与 Fuchsia 软件包没有直接关系。CIPD 支持在“软件包”的同一路径名称下存储多个“实例”,以及将“标记”和“引用”附加到实例。变体元信息在存储的工件的路径名组成部分中进行编码。版本元信息在 CIPD 软件包实例的标记和参考中进行编码。产品构建流程通过滚动获取工件的固定版本,并始终根据花瓣工件的固定版本构建产品。

图 2 - 当前系统结构 当前系统中所有协作部分的关系

通过工件存储区传播扩展的元信息

此处建议的设计更改了工件存储区的结构,以保留已发布工件的元信息属性。然后,产品可以根据属性值指定的条件选择合适的工件。

设计涉及三个额外的配置文件,以及三个用于对配置文件执行操作以与工件存储区进行交互的工具。这些文件是 artifact_groups.json,保存在工件存储区中;artifact_spec.jsonartifact_lock.json,保存在产品集成代码库中。uploadupdatefetch 工具会对文件和工件执行操作(如图 3 所示),如下所示:

  1. 每个来自某个 Peal 或 Fuchsia 构建流程的工件的新版本都会在与源代码库关联的工件存储区内创建一个新的工件组。已发布工件的属性记录在文件 artifact_groups.json 中,该文件也保存在工件存储区中。
    • Petal Build Process 使用 upload 工具将新发布的工件发布到工件存储区并更新 artifact_groups.json 文件。
  2. 在产品集成代码库中,artifact_spec.json 文件保留了列表,其中列出了从哪些工件存储区获取此集成代码库中的产品组装的工件,以及这些工件具有哪些属性。
    • update 工具用于使用集成代码库中的 artifact_spec.json 文件和 artifact_spec.json 文件中列出的所有工件存储区中的 artifact_groups.json 文件,选择要实际用于组装的工件集。
  3. update 工具选择的一组工件存储在 artifact_lock.json 文件中。
    • fetch 工具会下载 artifact_lock.json 文件中提及的所有工件,以使其可供集成代码库中的产品构建流程使用。

这些工具与构建规则的执行有何关系,取决于产品集成代码库中使用的特定构建系统。如需更多讨论,请参阅实现部分。

这些工具允许集成代码库中存在多个 artifact_spec.jsonartifact_lock.json 文件。

图 3 - 所有协作部分的关系 提议系统中所有合作部分的关系

工件存储区内的逻辑结构

工件存储区内的工件和工件组生成的逻辑结构如以下示例所示:

└── artifact_groups
          |
          ├── 92d483e5-ac7d-4029-a7db-e2ee6a8365c7
          |           |
          |           ├── web_engine
          |           |
          |           └── cast_runner
          |
          └── c907ff3f-cb15-4a7f-bb79-8cc23c0ff445
                      |
                      ├── web_engine
                      |
                      └── cast_runner

一组工件的每个版本都以不透明的名称显示,每个工件显示为组中的一个条目,并且具有可识别的名称。

此结构将与版本和各个工件的关联属性一起记录为 artifact_groups.json 文件中的 JSON 数据结构,详见下文。

工件和群组名称的使用

JSON 数据使用组名称和工件名称将记录的属性与其描述的工件相关联。组和工件的名称用于在文件 artifact_spec.json 中选择工件进入产品组装工作区的表达式中引用它们。工件名称还用作文件名,fetch 工具会在文件名下存储其本地下载的副本。

但是,这两个名称都不能用来指定工件在工件存储区中的存储位置。相反,所有工件都存储在其内容地址下,并且每个工件的内容地址都会作为 merkle 属性记录在 artifact_groups.json 中。

使用的内容地址是工件直接内容的紫红色Merkle 根。某些工件(具体来说是 Fuchsia 软件包)由其他存储组件(“blob”)表示,这些组件以传递方式包含在工件的直接内容中。这些附加组件存储在其内容地址下,但未在 artifact_groups.json 中明确提及。

唯一性不变

有几个唯一性不可变性需要在工件存储区中维护。这些不变量可保证通过引用工件的名称和属性来明确选择工件:

  1. 组名称在工件存储区内在整个历史记录中必须是唯一的。
  2. 工件名称在每个组内必须是唯一的。
  3. 一个组中每个工件的属性在工件存储区当前的所有组中同名的所有工件中必须是唯一的。

在将新的工件组添加到工件存储区时,upload 工具会维护这些唯一性不变性。update 工具还会检查唯一性,如果其访问的所有 artifact_group.json 文件的不变量未满足,则该工具会拒绝计算更新。工件存储区本身不需要在维护这些不变量方面发挥任何作用。

群组名称不透明

人们倾向于以属性值命名工件组,以使工件存储区更易懂或更易于导航。但是,这只有在属性数量固定一组时才能正常运行。当属性集扩展为多个属性和一组开放属性后,基于它们构建名称变得很繁琐,仅仅因为其架构的第一次组合爆炸(每个集合中可能的属性值的中间值或中间值的唯一爆炸。此外,读取此类名称不再那么容易,并且保持唯一性不变(尤其是跨历史记录)也更麻烦。

因此,由于此设计专门用于支持大型开放属性集,因此将选择不透明的组名称并满足所需唯一性不变性。在上面的示例中,组名称是随机 UUID。另一种方法是使用单调递增的填充整数。

artifact_groups.json 文件

artifact_groups.json 文件列出了所有组、包含的工件以及该工件存储区内的关联属性。

以下示例显示了与上面所示的工件存储区示例对应的 artifact_groups.json。属性与工件组相关联,在这种情况下,所有属性均适用于该组中的所有工件。属性也可以仅应用于单个工件。

此设计并未规定属性集本身。所有属性均由在源代码库中生成工件的构建和发布流程选择和分配。分配的属性只是保持上述唯一性不变。

{
  "schema_version": "https://fuchsia.dev/schemas/artifact_groups_schema.json",
  "version": 15,
  "artifact_groups": [
    {
      "name": "92d483e5-ac7d-4029-a7db-e2ee6a8365c7",
      "attributes": {
        "petal": "chromium.org",
        "version": "chrominum_release_20210304",
        "architecture": "arm64",
        "sdk_version": "2.20210303.3.1",
        "creation_time": "1622696983",
        "commit": "b26e44e9910608a2d0aec9b38e003a04a2da06df"
      },
      "artifacts": [
        {
          "name": "web_engine",
          "merkle":"90f67b10ded655852acb78a852ac5451486fc1e7378ce53368386244ce8f6e66",
          "type": "package",
          "attributes": {
            "runner_version": "2.20210301.1.3"
          }
        },
        {
          "name": "cast_runner",
          "merkle": "3394db36d228f4c719d055c394938c5a881ca6eea7ad3af0ad342e764cadc8b3",
          "type": "package"
        }
      ]
    },
    {
      "name": "c907ff3f-cb15-4a7f-bb79-8cc23c0ff445",
      "attributes": {
        "petal": "chromium.org",
        "version": "chrominum_release_20210402",
        "architecture": "arm64",
        "sdk_version": "2.20210303.3.4",
        "creation_time": "1622157425",
        "commit": "2dd76ad2298dfb869ef83c10b84b62485dc8a573"
      },
      "artifacts": [
        {
          "name": "web_engine",
          "merkle": "acb78a852ac5451486fc1e7378ce53368386244ce8f6e6690f67b10ded655852",
          "type": "package",
          "attributes": {
            "runner_version": "2.20210225.1.4"
          }
        },
        {
          "name": "cast_runner",
          "merkle": "19d055c394938c5a881ca6eea7ad3af0ad342e764cadc8b33394db36d228f4c7",
          "type": "package"
        }
      ]
    }
  ]
}

artifact_groups 列表中的每个组对象都包含 3 个属性:name 是组的名称,artifacts 是组中的工件列表,attributes 是组中的所有工件共享的属性。

仅适用于单个工件的属性会包含在表示该工件的对象中。此工件的属性会附加到该组的属性,以获取完整的工件属性集。

版本号是一个单调递增的数字。update 工具使用此编号来防止意外回滚到较低版本的 artifact_groups.json 文件。

工件组及其属性的可变性

在典型的使用场景中,一组工件的每个已发布的 build 都被记录为一个新组。因此,群组名称、群组中的工件以及群组的大多数属性在概念上都是不可变的。例外情况是指反映工件发布后出现的工件相关信息的属性。例如,在对工件发布后执行的手动测试中的工件的测试结果状态发生变化。反映此类信息的属性可能会更新。

但原则上,没有什么可以阻止工件组内容以及名称或属性随时间而变化。可以认为,这种方法可以在产品组装流水线中使用,但并不能用在目标应用中(请参阅下面的实现部分)。

产品构建流程

集成代码库中的产品构建流程会建立一个名为“规范文件”的 artifact_spec.json 文件。此文件列出了产品需要在集成代码库中组建的工件、要从中获取这些工件的工件存储区,以及工件属性的模式和约束条件。同样说明了工件存储区的类型,在一个规范文件中可以共存多种不同类型的工件存储区。

具体而言,预构建工件可以存储在集成代码库本身中,并且可以在规范文件中作为从“local”类型的工件存储区引用。

集成代码库中的产品构建流程使用 update 工具匹配规范文件中提及的所有工件存储区中的 artifact_groups.json 文件,并计算一组要使用的特定工件变体和版本。此集合记录在 artifact_lock.json 文件中。此文件将作为源文件提交至代码库中。

fetch 工具会读取 artifact_lock.json 文件,并将所有工件下载到集成代码库。工件不应作为源文件提交至代码库。不过,在 artifact_lock.json 文件中,系统会依据从 artifact_groups.json 文件获取的内容地址来标识这些工件。这样可以确保 artifact_lock.json 的提交内容完全决定了提供给 build 的工件的内容,从而使产品组装 build 相对于 artifact_lock.json 文件中选择的工件而言是封闭的且可重现。

实现

此处建议的设计将首先实现,以将工作站产品集成移至单独的仓库

如需了解 artifact_spec.json 的所需详细信息以及如何针对 artifact_groups.json 文件处理该文件以生成 artifact_lock.json 文件,请参阅另一个 RFC

迁移现有花瓣和产品

只要 Fuchsia 源代码树中仍然需要 petal 预构建版本(通过 integration.git 设置),它们就需要同时上传到 CIPD,以供 Fuchsia 源代码树中的 gn 构建规则使用,以及树外商品使用的工件存储区。最终,Fuchsia 源代码树中不再需要某些 petal 预构建文件,并且上传到 CIPD 的上传可能会停止。

我们无意取代使用 jiri 自行设置 Fuchsia 源代码树的机制,因为所有 Fuchsia 平台工件、SDK 和部分产品都是继续基于 Fuchsia 源代码树构建。

制品商店

工作站及其花瓣的实现将使用 TUF 代码库作为工件存储区。TUF 代码库的 targets.json 文件中的唯一条目是 artifact_groups.json 文件。工件本身存储在内容寻址的 blob 存储区(由用于 Fuchsia 的 TUF 服务器基础架构维护)中,其对应的 blob 地址记录在 artifact_groups.json 文件中。

此外,工件也可以在 targets.json 中的目录和工件名称下列出,但此设计中没有任何内容。(出于历史完整性的考虑,我们在此仅提及这一点,因为以前是为了防止有人知道 targets.json 条目。请参阅下面的替代方案部分。)

Fuchsia 软件包结构依赖项

本文提出的三个与工件存储区交互(上传、更新、提取)的工具在 Fuchsia 软件包上运行,因此对 Fuchsia 软件包的结构做出假设。具体而言,假设 Fuchsia 软件包包含一个 meta.far blob,其中包含同样属于该软件包的其他 blob 的内容地址(以 Merkle 根表示)。meta.far 中引用的 blob 列表是使用 Fuchsia SDK 提供的工具获取的,因此工件存储工具(上传、更新、提取)不依赖于 meta.far 的内部结构。

工具与构建规则的关系

uploadupdatefetch 工具与构建规则的执行之间的关系取决于源代码代码库中的特定构建系统、产品集成代码库,以及执行构建所需的基础架构。

upload 工具应在构建系统完成构建后执行。

通常,update 工具应在构建规则之外使用,然后构建执行。

fetch 工具可以在执行构建规则之前使用,也可以在构建系统支持的情况下使用,作为构建系统执行的一部分。对于工作站,bazel 用作构建系统,该系统支持设置“工作区规则”中的输入文件集。

工具可执行文件的名称

uploadupdatefetch 工具最终可以使用本设计中使用的概念名称以外的其他名称实现。具体而言,它们可以作为 ffx 工具的插件实现,也可以作为 bazel 构建规则生成的工具来实现。初始原型会将它们实现为名为 artifact_upload.pyartifact_update.pyartifact_fetch.py 的 Python 脚本。

文件语法

artifact_groups.json 文件的语法由以下 JSON 架构提供。artifact_spec.jsonartifact_lock.json 文件的 JSON 架构记录在单独的 RFC 中。

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "https://fuchsia.dev/schemas/artifact_groups_schema.json",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "contents",
    "schema_version",
    "version"
  ],
  "properties": {
    "schema_version": {
      "type": "string"
    },
    "version": {
      "type": "integer"
    },
    "artifact_groups": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string"
          },
          "attributes": {
            "type": "object"
          },
          "artifacts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "name",
                "merkle",
                "type",
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "merkle": {
                  "type": "string"
                },
                "attributes": {
                  "type": "object"
                },
                "type": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}

文件语义

此处介绍了 artifact_groups.json 的文件格式语义。artifact_spec.jsonartifact_lock.json 的详细语义再次记录在单独的 RFC 中。

{
  "schema_version": SCHEMA_VERSION,
  "version": VERSION,
  "artifact_groups": [
    ARTIFACT_GROUP,
    ...
  ]
}

SCHEMA_VERSION

指示 artifact_groups.json 的 JSON 架构网址的字符串。

版本

一个整数,表示 artifact_groups.json 的版本号。发布新版本时,此数字应该会增加。

ARTIFACT_GROUP

每个 ARTIFACT_GROUP 都是一个格式如下的对象:

{
  "name": NAME,
  "attributes": ATTRIBUTES,
  "artifacts": [
    ARTIFACT,
    ...
  ]
}

姓名

一个字符串,提供引用此工件组的方法。

属性。

由发布商定义的对象。

工件

每个 ARTIFACT 都是一个格式如下的对象:

{
  "name": NAME,
  "merkle": MERKLE,
  "type": TYPE,
  "attributes": ATTRIBUTES
},

姓名

包含此工件名称的字符串。

梅克莱

工件的默克尔根字符串。

类型

包含此工件类型的字符串。如果 TYPE"package",则其 Merkle 根引用的 blob 中的这个工件是紫红软件包的 meta.farmeta.far 中传递方式引用的 blob 始终与 元.far blob 一起处理。否则,该工件仅包含列出了 Merkle 的单个 blob。

属性

一个类似于上面定义的 ATTRIBUTES 的对象。您可以在此处定义工件专属属性。

安全注意事项

此 RFC 中的设计不会更改现有操作者之间的信任模型。此机制只会更改存储结构,而不会更改使用工件存储区的各操作者之间或操作者与工件存储区之间的信任关系。

信任模型

与目前使用 CIPD 作为工件存储区一样,产品构建流程需要信任工件存储区。目前,这种信任基于工件存储区提供给 Peal 和 Fuchsia build 进程的访问权限控制和身份验证,以及构建基础架构和环境来解析工件存储区的已配置名称,以访问正确的工件存储区。

一旦建立了更多的工件存储区和产品集成代码库,就需要评估对它们的信任基础,并相应地评估组装产品的可信度。

将来,除了当前所用机制之外,您还可以建立其他机制,例如对 TUF 代码库中的签名等签名的验证。此处设计的机制可以支持相关信息的传播,这些信息用于评估可信度,但此类信息的创建是正交的。

特别是对于 TUF 签名,请务必注意,此类签名只能提供证据来支持托管工件的代码库的可信度。它本身并不能构成评估从该工件中获取的工件的可信度的完整基础,因为这还取决于对签名密钥的控制、生成工件的构建流程的可信度,以及构建流程用作输入的传递来源和工具的可信度。对于目前用于 Fuchsia 产品的 TUF 实现(用于对上传到维护代码库的服务的任何工件进行签名),这还取决于 ACL 的完整性以及允许客户端访问该服务的身份验证机制。

多个花瓣 build 流程发布到同一工件存储区

建议发布源代码库不要共享工件存储区,这样,无论这种信任关系是如何建立的,都不必与服务器共享信任关系。例如,对于 TUF 实现,发布者不必共享签名密钥。

此外,还有一些潜在的妥协,即发布到同一工件存储区的多个花瓣构建流程。例如,一个发布者可能会覆盖另一个发布者发布的工件。但这超出了此 RFC 的范围,因为在此 RFC 中,发布到工件存储区的所有花瓣 build 流程均由同一组织运营,因此可以进行适当的协调。如果我们希望将其扩展到多个组织,则需要设计不同的协调模型。

性能

随着 artifact_groups.json 文件中的项数越来越大,查找与所有必需属性匹配的组的时间复杂程度至少会线性增加。如果工件之间存在约束,则可能是超线性的,因为更新工具需要联接多个 artifact_groups.json 文件才能执行选择。工件发布者可能需要逐出太旧的工件组,以帮助提高客户端更新工具的性能。

对于大型商品,选择工件后下载时间可能会很长。这与现状是一样的。与全局集成相比,此处介绍的设计具有优势,即 fetch 工具一次只能将一个产品的预构建工件下载到任何一个集成仓库中。在当前的全球集成中,需要在 jiri update 期间下载所有已知产品的预构建工件的并集。

隐私注意事项

存储在工件存储区中的唯一新数据是 artifact_groups.json 文件。工件存储区的发布者不应在 artifact_groups.json 文件中发布个人身份信息。

测试

这些工具使用的库(例如用于将 artifact_spec.json 文件中的属性模式与 artifact_groups.json 文件匹配的库)将由单元测试进行测试。

对于将工具作为可执行文件操作的操作,将通过本地保留的黄金文件运行集成测试。

对于端到端测试,其自己的代码库中会有“Hello World”产品,该产品可持续运行机械,并可以针对故障进行监控。

缺点、替代方案和未知因素

使用其他类型的工件存储区

除了 TUF 之外,您还可以使用其他工件存储区。例如:

  • CIPD,
  • 静态 HTTPS 服务器
  • GCS 存储分区
  • Git 代码库。

您可以在所有这些工件存储区内创建适当的结构,以便将工件放在名称下作为其内容地址的位置,并且可以在 artifact_groups.json 文件中维护元数据,具体方式与在上述实现方案中使用的 TUF 代码库中的相同。

每个版本的 TUF 代码库

此设计的早期版本采取的另一个替代方案是每个工件版本的 TUF 代码库。upload 工具会创建新的 TUF 代码库来托管工件,而不是为版本的所有工件创建组。众所周知的查询代码库包含记录属性的 artifact_groups.json 文件。它将包含每个工件组的代码库名称,而不是组名称。

这种方法的优势在于,支持使用仅在首次使用时向设备分发的临时软件包的产品。除了或补充将软件包添加到产品组件集的此类发布代码库中,该代码库还会作为软件包来源包含在产品中,用于在运行时解析软件包网址。

这种使用设计被拒绝了,因为此类产品目前尚不存在,并且当前的设备和 TUF 基础架构中软件交付机制(尽管专为此类用途而设计)从未证明能够以这种方式在生产环境中使用,并且预计会在可行之前进一步发展。因此,他们强烈渴望实现不锁定于软件交付的当前状态。同样,TUF 基础架构也无法很好地处理大量 TUF 代码库。

TUF 代码库的 targets.json 中列出的所有工件

最初,人们希望所有工件(尤其是所有 Fuchsia 软件包)都会列在 TUF 代码库的 targets.json 文件中,并且对一个版本中工件进行分组的目录是包含 TUF 代码库目标的实际目录。该信息与 artifact_groups.json 中已记录的信息重复,并且没有任何用途,因此为清楚起见,我们丢弃了该信息,以及为避免对 targets.json 施加的大小限制(该限制并未对仅在 targets.json 中列出的文件施加)。

未知

关于上述设计的应用扩展,目前有一些问题尚未解决。

  • 此机制是否也可应用于 Fuchsia SDK?Fuchsia SDK 是创建花瓣组件和树外商品的必要工件,就像预构建工件是创建商品的先决条件一样。您需要根据变体和版本(基于描述两者的属性)以非常相似的方式选择该工件。因此,一个问题是,花瓣构建流程是否应在 artifact_spec.json 文件中声明它们对 SDK 的使用,以及产品构建流程是否应在其 artifact_spec.json 文件中包含 Fuchsia SDK。
  • 此机制是否也可应用于花瓣 SDK,即一片花瓣为其他花瓣提供的 SDK,如 Flutter SDK?这并不是启用分散式产品集成的必要条件,但可以简化生成的分布式构建流程。例如,通过在 petal 代码库的 lock 文件中检查提取的 Flutter SDK 版本,上传工具可以找出所上传工件的正确 Flutter SDK 版本属性值。
  • 此机制是否也可用于发布构建的产品?在工作站实现中,fuchsia 工作站产品可以发布到工件存储区。上传的产品以后可用于差分组装。
  • 说明机制能否用于以递归方式为创建产品所涉及的所有二进制工件、返回到产品中包含的预构建工件、用于组装产品的工具的预构建工件、用于创建预构建工件的工具等建立传递性的二进制文件透明度。

文档

本文档为初始文档。我们将提供各种工具 以及帮助页面工作站代码库设置将充当后续使用的蓝图和演示。

现有艺术和参考资料

其他操作系统的产品集成通常在源代码树中进行,且使用预构建版本较少,因此在代码库之间并发传播此类预构建版本的多个变体和版本的要求较低。

构建系统只需在由当前应用的构建参数确定的变体中在当前版本中重新构建依赖项,即可“选择”该依赖项的兼容“版本”。此处介绍的设计可以理解为用于异步和分布式运行的构建系统的泛化。

附录

图 4 - 全球集成图图例 全球集成图图例