Docker サンドボックスを使用した Bazel リモート実行のトラブルシューティング

ローカルで成功した Bazel ビルドがリモートで実行されると、 ローカルビルドには影響しない制限や要件が原因で失敗することがあります。このような失敗の最も一般的な 原因については、リモート実行用に Bazel ルールを調整するをご覧ください。

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

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

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

  • 余分なデータがコンテナの境界を越えることはありません。明示的に 宣言された入力と出力のみがコンテナに出入りし、関連するビルド アクションが正常に完了した後にのみ 出入りします。

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

これらの問題は、次のいずれかの方法でトラブルシューティングできます。

  • ネイティブにトラブルシューティングする。この方法では、 Bazel とそのビルド アクションがローカルマシンでネイティブに実行されます。Docker サンドボックス機能では、リモート 実行と同じビルド制限が適用されます。ただし、この方法では、ローカルツール、状態、および データがビルドにリークしていることを検出できません。これにより、リモート実行で問題が発生します。

  • Docker コンテナでトラブルシューティングする。 この方法では、Bazel とそのビルド アクションが 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

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

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

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

ネイティブにトラブルシューティングする

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

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

  • 絶対パスまたは 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 ソケットをマッピングして mounting the /tmp ディレクトリをマウントします。これにより、Bazel は他の Docker コンテナを生成し、 /tmp の下のディレクトリを使用してこれらのコンテナとファイルを共有できます。ソース コードはコンテナ内の /src にあります。

このコマンドは、ツールチェーン コンテナとして使用される rbe-ubuntu16-04 コンテナと互換性のないバイナリを含む debian:stretch ベースコンテナから意図的に開始されます。ローカル環境のバイナリが ツールチェーン コンテナにリークすると、ビルドエラーが発生します。

ステップ 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: 検出された問題を解決するのトラブルシューティングの手順をご覧ください。