ローカルで成功した 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
ルールに追加のツールが必要な場合は、次のようにします。
Dockerfile を使用してツールをインストールし、ローカルでイメージをビルドして、カスタム Docker コンテナを作成します。
上記の
--experimental_docker_image
フラグの値は、カスタム コンテナ イメージの名前に置き換えます。
ネイティブ トラブルシューティング
この方法では、Bazel とそのすべてのビルド アクションをローカルマシンで直接実行します。これは、リモートで実行されたときにビルドが成功するかどうかを確認する信頼できる方法です。
ただし、この方法では、特に configure スタイルの WORKSPACE ルールを使用している場合、ローカルにインストールされたツール、バイナリ、データがビルドに漏洩する可能性があります。このようなリークはリモート実行で問題を引き起こします。これを検出するには、ネイティブのトラブルシューティングに加えて、Docker コンテナでトラブルシューティングを行います。
ステップ 1: ビルドを実行する
ビルドを実行する Bazel コマンドに
--config=docker-sandbox
フラグを追加します。次に例を示します。bazel --bazelrc=.bazelrc build --config=docker-sandbox target
ビルドを実行し、完了するまで待ちます。Docker サンドボックス機能により、ビルドの実行速度は通常の 4 倍遅くなります。
次のエラーが発生することがあります。
ERROR: 'docker' is an invalid value for docker spawn strategy.
存在する場合は、--experimental_docker_verbose
フラグを指定してビルドを再度実行します。このフラグを使用すると、詳細なエラー メッセージが有効になります。このエラーは通常、Docker のインストールに問題があるか、現在のユーザー アカウントで Docker を実行する権限がない場合に発生します。詳細については、Docker のドキュメントをご覧ください。問題が解決しない場合は、Docker コンテナでのトラブルシューティングに進みます。
ステップ 2: 検出された問題を解決する
以下に、よくある問題とその回避策を示します。
Bazel runfiles ツリーで参照されているファイル、ツール、バイナリ、またはリソースがありません。影響を受けるターゲットのすべての依存関係が明示的に宣言されていることを確認します。詳細については、暗黙的な依存関係の管理をご覧ください。
絶対パスまたは
PATH
変数によって参照されるファイル、ツール、バイナリ、またはリソースがない。必要なすべてのツールがツールチェーン コンテナ内にインストールされていることを確認します。また、ツールチェーン ルールを使用して、不足しているリソースを指す依存関係を適切に宣言します。詳細については、ツールチェーン ルールによるビルドツールの呼び出しをご覧ください。バイナリの実行が失敗します。いずれかのビルドルールが、実行環境(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: コンテナをビルドする
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
コンテナを
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
にあります。
このコマンドは、ツールチェーン コンテナとして使用される 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: 検出された問題を解決するのトラブルシューティングの手順をご覧ください。