Docker Sandbox を使用した Bazel リモート実行のトラブルシューティング

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。
問題を報告する ソースを表示

ローカルで成功する Bazel ビルドは、ローカルビルドに影響しない制限と要件により、リモートで失敗する可能性があります。このような障害の一般的な原因については、Bazel ルールをリモート実行に適応させるをご覧ください。

このページでは、Docker サンドボックス機能を使用して、リモート実行で発生する最も一般的な問題を特定して解決する方法について説明します。この機能を使用すると、リモート実行の場合と同等の制限がビルドに適用されます。これにより、リモート実行サービスを必要とせずにビルドのトラブルシューティングを行うことができます。

Docker サンドボックス機能は、次のようにリモート実行の制限を模倣します。

  • ビルド アクションをツールチェーン コンテナで実行する。同じツールチェーン コンテナを使用して、コンテナ化されたリモート実行をサポートするサービスを介して、ローカルとリモートでビルドを実行できます。

  • 外部データがコンテナの境界を越えていない。明示的に宣言された入力と出力のみが、コンテナに入るかコンテナから出て、関連するビルド アクションが正常に完了した後に限ります。

  • 各アクションは新しいコンテナで実行されます。生成されたビルド アクションごとに、新しい一意のコンテナが作成されます。

これらの問題のトラブルシューティングを行うには、次のいずれかの方法を使用します。

  • ネイティブでのトラブルシューティング。この方法では、Bazel とそのビルド アクションがローカルマシンでネイティブに実行されます。Docker サンドボックス機能では、リモート実行の場合と同等のビルドに制限が課されます。ただし、ローカルツール、状態、ビルドへのデータ漏洩は検出されないため、リモート実行で問題が発生します。

  • Docker コンテナでのトラブルシューティング。この方法では、Bazel とそのビルド アクションが Docker コンテナ内で実行されるため、ローカルマシンからビルドへのツール、状態、データの漏洩を検出できます。また、リモート実行と同等の制限を課すこともできます。この方法では、ビルドの一部が失敗した場合でも、ビルドに関する分析情報が提供されます。この方法は試験運用版であり、正式にはサポートされていません。

Prerequisites

トラブルシューティングを開始する前に、次の手順を行ってください(まだ行っていない場合)。

  • 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

ルールで追加のツールが必要な場合は、次の操作を行います。

  1. Dockerfile を使用してツールをインストールし、イメージをビルドしてカスタム Docker コンテナを作成します。

  2. 上記の --experimental_docker_image フラグの値は、カスタム コンテナ イメージの名前に置き換えます。

ネイティブでのトラブルシューティング

この方法では、Bazel とそのすべてのビルド アクションがローカルマシン上で直接実行されるため、リモートでビルドに成功した場合に信頼性の高い方法で確実にビルドできます。

ただし、この方法では、特に構成スタイルの WORKSPACE ルールを使用している場合に、ローカルにインストールされたツール、バイナリ、データがビルドにリークする可能性があります。この漏えいによってリモート実行で問題が発生し、ネイティブのトラブルシューティングだけでなく、Docker コンテナでのトラブルシューティングも検出されます。

ステップ 1: ビルドを実行する

  1. ビルドを実行する Bazel コマンドに --config=docker-sandbox フラグを追加します。例:

    bazel --bazelrc=.bazelrc build --config=docker-sandbox target
    
  2. ビルドを実行し、完了するまで待ちます。Docker サンドボックス機能により、ビルドの実行速度は最大で 4 倍遅くなります。

次のエラーが発生することがあります。

ERROR: 'docker' is an invalid value for docker spawn strategy.

その場合は、--experimental_docker_verbose フラグを使用してビルドを再度実行します。このフラグは、詳細なエラー メッセージを有効にします。このエラーは通常、Docker のインストールが正しくないか、現在のユーザー アカウントでアプリケーションを実行する権限がないために発生します。詳細については、Docker のドキュメントをご覧ください。問題が解決しない場合は、Docker コンテナでのトラブルシューティングに進んでください。

ステップ 2: 検出された問題を解決する

以下では、よく発生する問題とその回避策について説明します。

  • Bazel runfiles ツリーで参照されるファイル、ツール、バイナリ、またはリソースが見つかりません。影響を受けるターゲットのすべての依存関係が明示的に宣言されていることを確認します。詳細については、暗黙的な依存関係の管理をご覧ください。

  • 絶対パスまたは PATH 変数によって参照されるファイル、ツール、バイナリ、またはリソースがありません。必要なすべてのツールがツールチェーン コンテナにインストールされていることを確認し、ツールチェーン ルールを使用して、欠落しているリソースを指す依存関係を正しく宣言します。詳しくは、ツールチェーン ルールを使用したビルドツールの呼び出しをご覧ください。

  • バイナリの実行が失敗します。ビルドルールの 1 つは、実行環境(Docker コンテナ)と互換性のないバイナリを参照しています。詳細については、プラットフォーム依存のバイナリの管理をご覧ください。問題を解決できない場合は、bazel-discuss@google.com にお問い合わせください。

  • @local-jdk のファイルがないか、エラーが発生する。ローカルマシン上の Java バイナリがビルドにリークしながら、互換性がありません。ルールとターゲットでは、@local_jdk ではなく java_toolchain を使用します。サポートが必要な場合は、bazel-discuss@google.com にお問い合わせください。

  • その他のエラー。bazel-discuss@google.com にお問い合わせください。

Docker コンテナでのトラブルシューティング

この方法では、Bazel はホストの Docker コンテナ内で実行され、Bazel のビルド アクションは Docker サンドボックス機能によって生成された個々のツールチェーン コンテナ内で実行されます。サンドボックスでは、ビルド アクションごとに新しいツールチェーン コンテナが生成され、各ツールチェーン コンテナでは 1 つのアクションのみが実行されます。

この方法では、ホスト環境にインストールされているツールをより細かく制御できます。ビルドの実行とビルド アクションの実行を分離し、インストールされているツールを最小限にすることで、ビルドがローカル実行環境に依存しているかどうかを検証できます。

ステップ 1: コンテナをビルドする

  1. Docker コンテナを作成し、最小限のビルドツールで Bazel をインストールする Dockerfile を作成します。

    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
    
  2. コンテナを 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: ビルドを実行する

以下のようにビルドを実行します。出力ユーザーは root であるため、Bazel が実行されているホストコンテナ内から、Bazel のビルド アクションが実行されている Docker サンドボックス機能によって生成されたツールチェーン コンテナから、ホストとアクション コンテナが実行されているローカルマシンから、同じ絶対パスでアクセスできるディレクトリにアクセスできます。

bazel --output_user_root=/tmp/bazel_docker_root --bazelrc=.bazelrc \ build --config=docker-sandbox target

ステップ 5: 検出された問題を解決する

ビルドの失敗は、次の方法で解決できます。

  • 「ディスク容量不足」エラーでビルドが失敗した場合は、--memory=XX フラグを指定してホストコンテナを起動することで、この上限を増やすことができます(XX はギガバイト単位で割り当てられたディスク容量です)。これは試験運用版であり、予期しない動作が発生する可能性があります。

  • 分析フェーズまたは読み込みフェーズでビルドが失敗した場合、WORKSPACE ファイルで宣言されている 1 つ以上のビルドルールがリモート実行と互換性がありません。考えられる原因と回避策については、リモート実行に Bazel ルールを適応させるをご覧ください。

  • その他の理由でビルドに失敗した場合は、ステップ 2: 検出された問題を解決するのトラブルシューティングの手順をご覧ください。