在本地成功的 Bazel 构建在远程执行时可能会失败,因为存在一些限制和要求不会影响本地构建。将 Bazel 规则调整为远程执行介绍了导致此类失败的最常见原因。
本页面介绍了如何使用 Docker 沙盒功能识别和解决远程执行时最常出现的问题,该功能会对构建施加与远程执行等同的限制。这样,您无需远程执行服务即可排查 build 问题。
Docker 沙盒功能模拟了远程执行的限制,如下所示:
构建操作在工具链容器中执行。您可以使用相同的工具链容器,通过支持容器化远程执行的服务在本地和远程运行构建。
没有任何外部数据会跨越容器边界。只有明确声明的输入和输出才会进入和离开容器,并且只有在关联的构建操作成功完成之后。
每个操作都是在新容器中执行。系统会为每个生成的构建操作创建一个新唯一容器。
您可以使用以下方法之一排查这些问题:
原生问题排查。使用此方法,Bazel 及其构建操作在本地机器上以原生方式运行。Docker 沙盒功能会对构建施加与远程执行等同的限制。但是,此方法无法检测泄露到 build 的本地工具、状态和数据(这些数据会导致远程执行出现问题)。
在 Docker 容器中进行问题排查。 通过这种方法,Bazel 及其构建操作在 Docker 容器内运行,这样除了施加与远程执行同等的限制之外,您还可以检测从本地机器泄露到构建中的工具、状态和数据。即使构建的某些部分失败,此方法也能提供有关构建的深入信息。此方法处于实验阶段,尚未获得官方支持。
前提条件
在开始排查问题之前,请先执行以下操作(如果您尚未这样做):
- 安装 Docker 并配置运行 Docker 所需的权限。
- 安装 Bazel 0.14.1 或更高版本。较低版本不支持 Docker 沙盒功能。
- 按照此处所述,将固定到最新发布版本的 bazel-toolchains 代码库添加到构建的
WORKSPACE
文件中。 - 将标志添加到
.bazelrc
文件以启用该功能。如果该文件不存在,请在 Bazel 项目的根目录中创建该文件。以下标志是参考示例。请参阅 bazel-toolchains 代码库中的最新.bazelrc
文件,并复制其中为配置docker-sandbox
定义的标志的值。
# Docker Sandbox Mode
build:docker-sandbox --host_javabase=<...>
build:docker-sandbox --javabase=<...>
build:docker-sandbox --crosstool_top=<...>
build:docker-sandbox --experimental_docker_image=<...>
build:docker-sandbox --spawn_strategy=docker --strategy=Javac=docker --genrule_strategy=docker
build:docker-sandbox --define=EXECUTOR=remote
build:docker-sandbox --experimental_docker_verbose
build:docker-sandbox --experimental_enable_docker_sandbox
如果您的规则需要使用其他工具,请执行以下操作:
使用 Dockerfile 安装工具并在本地构建映像,从而创建自定义 Docker 容器。
将上述
--experimental_docker_image
标志的值替换为自定义容器映像的名称。
原生问题排查
此方法直接在本地机器上执行 Bazel 及其所有构建操作,是确认远程执行构建是否成功的可靠方法。
不过,使用此方法时,本地安装的工具、二进制文件和数据可能会泄露到您的 build 中,尤其是在 build 使用配置式 WORKSPACE 规则时。此类泄露会导致远程执行出现问题;如需检测此类泄露,除了以原生方式排查问题之外,还应在 Docker 容器中进行问题排查。
第 1 步:运行构建
将
--config=docker-sandbox
标志添加到执行构建的 Bazel 命令中。例如:bazel --bazelrc=.bazelrc build --config=docker-sandbox target
运行构建并等待构建完成。由于 Docker 沙盒功能的原因,构建的运行速度最多会比平常慢四倍。
您可能会遇到以下错误:
ERROR: 'docker' is an invalid value for docker spawn strategy.
在这种情况下,请使用 --experimental_docker_verbose
标志再次运行构建。此标志会启用详细错误消息。此错误通常是由于 Docker 安装有误或当前用户账号没有权限在其下执行 Docker 命令所致。如需了解详情,请参阅 Docker 文档。如果问题仍然存在,请直接跳到在 Docker 容器中进行问题排查。
第 2 步:解决检测到的问题
以下是最常遇到的问题及其解决方法。
缺少 Bazel runfiles 树引用的文件、工具、二进制文件或资源。确认已明确声明受影响目标的所有依赖项。如需了解详情,请参阅管理隐式依赖项。
缺少绝对路径或
PATH
变量引用的文件、工具、二进制文件或资源。确认工具链容器中是否安装了所有必需的工具,并使用工具链规则正确声明指向缺失资源的依赖项。如需了解详情,请参阅通过工具链规则调用构建工具。二进制文件执行失败。其中一个 build 规则引用的二进制文件与执行环境(Docker 容器)不兼容。如需了解详情,请参阅管理平台依赖的二进制文件。如果您无法解决问题,请与 bazel-discuss@google.com 联系以寻求帮助。
@local-jdk
中的某个文件缺失或导致错误。本地机器上的 Java 二进制文件会泄露到 build 中,但与 build 不兼容。在您的规则和目标中使用java_toolchain
(而非@local_jdk
)。如需进一步帮助,请发送电子邮件至 bazel-discuss@google.com。其他错误。请联系 bazel-discuss@google.com 以寻求帮助。
在 Docker 容器中进行问题排查
使用此方法,Bazel 会在主机 Docker 容器内运行,而 Bazel 的构建操作会在 Docker 沙盒功能生成的各个工具链容器内执行。沙盒会为每项构建操作生成一个全新的工具链容器,并且每个工具链容器中只有一个操作执行。
这种方法可对主机环境中安装的工具进行更精细的控制。通过将构建的执行与其构建操作的执行分离开来,并尽可能减少安装的工具,您可以验证构建是否对本地执行环境有任何依赖项。
第 1 步:构建容器
创建一个
Dockerfile
,用于创建 Docker 容器并使用一组最少的构建工具安装 Bazel:FROM debian:stretch RUN apt-get update && apt-get install -y apt-transport-https curl software-properties-common git gcc gnupg2 g++ openjdk-8-jdk-headless python-dev zip wget vim RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" RUN apt-get update && apt-get install -y docker-ce RUN wget https://releases.bazel.build/<latest Bazel version>/release/bazel-<latest Bazel version>-installer-linux-x86_64.sh -O ./bazel-installer.sh && chmod 755 ./bazel-installer.sh RUN ./bazel-installer.sh
以
bazel_container
构建容器:docker build -t bazel_container - < Dockerfile
第 2 步:启动容器
使用以下命令启动 Docker 容器。在该命令中,替换成主机上您要构建的源代码的路径。
docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp:/tmp \
-v your source code directory:/src \
-w /src \
bazel_container \
/bin/bash
此命令以 root 身份运行容器,映射 Docker 套接字并装载 /tmp
目录。这样一来,Bazel 便可生成其他 Docker 容器,还可以使用 /tmp
下的目录与这些容器共享文件。您的源代码位于容器内的 /src
。
该命令有意从 debian:stretch
基础容器开始,此容器包含与用作工具链容器的 rbe-ubuntu16-04
容器不兼容的二进制文件。如果本地环境中的二进制文件泄漏到工具链容器中,则会导致构建错误。
第 3 步:测试容器
在 Docker 容器内运行以下命令进行测试:
docker ps
bazel version
第 4 步:运行构建
如下所示运行 build。输出用户是 root 用户,因此它对应于可通过同一绝对路径从运行 Bazel 的主机容器内部、从运行 Bazel 构建操作的 Docker 沙盒功能生成的工具链容器,以及从运行主机和操作容器的本地机器访问的目录。
bazel --output_user_root=/tmp/bazel_docker_root --bazelrc=.bazelrc \ build --config=docker-sandbox target
第 5 步:解决检测到的问题
您可以通过以下方式解决构建失败问题:
如果构建失败并显示“磁盘空间不足”错误,您可以使用标志
--memory=XX
启动主机容器(其中XX
为分配的磁盘空间,以 GB 为单位),从而提高此限制。此功能处于实验阶段,可能会导致无法预测的行为。如果构建在分析或加载阶段失败,则表示 WORKSPACE 文件中声明的一个或多个构建规则与远程执行不兼容。如需了解可能的原因和权宜解决方法,请参阅针对 Remote Execution 调整 Bazel 规则。
如果构建因任何其他原因而失败,请参阅第 2 步:解决检测到的问题中的问题排查步骤。