为远程执行调整 Bazel 规则

报告问题 查看来源 每晚 · 7.2。 · 7.1敬上 · 7.0 · 6.5 条 · 6.4

本页面适用于编写自定义构建和测试规则的 Bazel 用户 希望了解 远程执行。

远程执行允许 Bazel 在单独的平台上执行操作,例如 数据中心Bazel 使用 gRPC 协议 远程执行。您可以尝试使用以下代码远程执行 bazel-buildfarm、 旨在提供分布式远程执行功能的开源项目 平台。

本页在提及不同的技术时使用了以下术语 环境类型或平台

  • 托管平台 - 运行 Bazel 的位置。
  • 执行平台 - 运行 Bazel 操作的地方。
  • 目标平台 - 构建输出(和某些操作)的运行位置。

概览

在配置 Bazel 构建以进行远程执行时,必须遵循 确保构建远程执行的 不会发生错误。这取决于远程执行的性质,即:

  • 隔离构建操作。构建工具不会保留状态和依赖项 它们之间不能泄露

  • 丰富多样的执行环境。本地构建配置并非总是如此 适合远程执行环境。

本页面介绍实现自定义 Bazel 时可能出现的问题 构建和测试远程执行规则以及如何避免这些规则。其中介绍了 以下主题:

通过工具链规则调用构建工具

Bazel 工具链规则是一个配置提供程序,用于告知构建规则 要使用的构建工具(例如编译器和链接器)以及如何配置这些工具 使用由规则创建者定义的参数工具链规则允许构建 和测试规则,以可预测的预配置方式调用构建工具 支持远程执行例如,使用工具链规则 而不是通过 PATHJAVA_HOME 或其他本地变量来调用构建工具 在远程容器中可能未设置为等效值(或根本没有)的变量, 执行环境

目前存在适用于 Bazel 构建和测试规则的工具链规则 ScalaRust、 和 Go, 新的工具链规则正在陆续针对其他语言和工具,例如 bash。 如果您的规则所用工具不存在工具链规则,请考虑 创建工具链规则

管理隐式依赖项

如果构建工具可以在构建操作之间访问依赖项,那么这些操作 远程执行时会失败,因为执行了每个远程构建操作 与众不同。有些构建工具会在构建操作和 访问此工具中未明确包含的依赖项 调用,这将导致远程执行的构建操作失败。

例如,当 Bazel 指示有状态编译器在本地构建 foo 时, 编译器会保留对 foo 的构建输出的引用。当运行 Bazel 时 会指示编译器构建依赖于 foobar,而不 在 BUILD 文件中明确指出要包含在 相应操作,那么只要与之前相同的 编译器实例会针对这两项操作执行(如同本地执行的典型情况)。 不过,由于在远程执行场景中,每个构建操作都会执行 单独的编译器实例、编译器状态和 Bar 的隐式依赖项 foo 将丢失,并且构建将失败。

为帮助检测并消除这些依赖关系问题,Bazel 0.14.1 提供了 本地 Docker 沙盒,其对依赖项的限制与远程容器相同 执行。使用沙盒为远程执行准备 build,方法是 识别和解决与依赖项相关的构建错误。请参阅对使用 Docker Sandbox 的 Bazel Remote Execution 进行问题排查

管理依赖于平台的二进制文件

通常,在托管平台上构建的二进制文件无法在 任意远程执行平台,因为依赖项可能不匹配。 例如,随 Bazel 提供的 SingleJar 二进制文件以主机平台为目标。 但是,对于远程执行,必须在进程中编译 SingleJar 构建代码,使其以远程执行平台为目标。(请参阅 目标选择逻辑。)

请勿随源代码一起交付 build 所需的构建工具的二进制文件 除非您确定它们会在您的执行平台中安全运行。相反, 以下项之一:

  • 发布该工具的源代码,或在外部引用该工具,以便能够对其进行编译 专为远程执行平台而构建。

  • 将该工具预安装到远程执行环境中(例如, 工具链容器),只要它足够稳定,然后使用工具链规则来运行 。

管理配置式 WORKSPACE 规则

Bazel 的 WORKSPACE 规则可用于探测主机平台中的工具 构建所需的库和库,对于本地构建而言,这也是 Bazel 的 执行平台构建是否明确依赖于本地构建工具和 工件,如果远程执行平台在远程执行期间 与托管平台不相同

WORKSPACE 规则执行的以下操作不兼容 远程执行:

  • 构建二进制文件 -正在 WORKSPACE 规则中执行编译操作 导致二进制文件与远程执行平台不兼容 (如果与托管平台不同)。

  • 安装 pip 软件包。已通过 WORKSPACE 安装了 pip 个软件包 规则要求其依赖项预安装在主机平台上。 专门为托管平台构建的此类软件包将 如果与主机不同,则与远程执行平台不兼容 平台。

  • 与本地工具或工件建立符号链接。指向工具或库的符号链接 安装在通过 WORKSPACE 规则创建的主机平台上会导致 构建在远程执行平台上失败,因为 Bazel 无法 找到它们。而是应该使用标准构建操作来创建符号链接,这样, 可以从 Bazel 的 runfiles 访问符号链接的工具和库 树。不使用 repository_ctx.symlink 对外部代码库目录之外的目标文件进行符号链接。

  • 更改主机平台。避免在 Bazel 之外创建文件 runfiles 树、创建环境变量以及类似的操作,如下所示: 它们可能会在远程执行平台上出现意外行为。

为了帮助您发现潜在的非封闭行为,您可以使用工作区规则日志

如果外部依赖项依赖于主机执行特定操作 您应在 WORKSPACE 和 build 之间拆分这些操作 规则如下:

  • 平台检查和依赖项枚举。这些操作包括 可通过WORKSPACE规则在本地执行 以及下载必须构建的软件包, 进行编译所需的工件对于远程执行,这些规则必须 也支持使用预先检查的工件来提供 通常在主机平台检查期间获得。预先选中 软件制品使 Bazel 能够像描述本地依赖项一样描述依赖项。使用 条件语句或 --override_repository 标志。

  • 生成或编译特定于目标的工件和平台变更。 这些操作必须通过常规构建规则执行。会 必须执行为外部依赖项生成特定于目标的工件 构建容器。

为了更轻松地生成预检查的工件以用于远程执行,您可以使用 使用 WORKSPACE 规则发出生成的文件。您可以在每个新订单 执行环境(例如在每个工具链容器内),然后检查 将远程执行构建的输出放入源代码库以供参考。

例如,对于 cuda 的 Tensorflow 规则, 和python WORKSPACE 规则会生成以下 BUILD files。 对于本地执行,将使用通过检查主机环境生成的文件。 对于远程执行,条件语句 则允许规则使用已签入到以下目录的文件: 代码库

BUILD 文件会声明 genrules 可在本地和远程运行,并执行必要的处理, 之前通过 repository_ctx.symlink 完成的调用,如此处所示。