セルフホスト型 Bare Metal Runner
セルフホスト型 Runner とは、Bencher が管理する On-Demand または Dedicated Runner を使う代わりに、
自分自身で実行・管理する Bare Metal Runner です。
runner バイナリを Bencher API サーバーに向けると、
自分自身のハードウェア上で Job を要求して実行します。
Runner のセルフホストは、次のような場合に適しています。
- Bencher Cloud が提供していない特定のハードウェア上でベンチマークを実行したい
- ベンチマークのワークロードを自分自身のネットワーク内やエアギャップ環境に保ちたい
- Bencher Self-Hosted をエンドツーエンドで実行したい
このガイドでは、Runner の登録、Spec によるそのハードウェアの記述、両者の連携、
そして runner バイナリの起動までを順に説明します。
Runner、Spec、Sandbox、Job がどのように組み合わさるかの概念的な概要については、
Bare Metal の概要 を参照してください。
🐰 Firecracker のサンドボックス化には、KVM が有効で、
/sys/fs/cgroupに書き込み可能な cgroup v2 階層がある Linux 5.14 以降が必要で、 Runner はrootとして実行する必要があります。 サンドボックス化された各 Job は、CPU コア数にかかわらず/sys/fs/cgroup/bencherの下にある専用の cgroup で実行され、cpuset、memory、pidsコントローラーが有効になります。 Runner は Job のプロセスをその cgroup のcgroup.killで終了させますが、これは古いカーネルにはありません。その場合 Runner は起動時に終了するか、--danger-allow-no-sandbox付きで起動していれば、サンドボックス化された各 Job を失敗させます。 サンドボックス化された各 Job を動かす Firecracker プロセスは非特権ユーザーとして chroot に閉じ込められ、 その閉じ込めの構築には、KVM を有効にするだけでは得られない権限が必要です。 サンドボックスなしの Spec のみを提供する Runner は、サポートされている任意のホスト上で実行できます。
Runner を作成する
Runner は、runner バイナリを Bencher API サーバーに対して認証するリソースです。
bencher CLI、Runners REST API、
または Bencher Console で作成します。
bencher runner create \ --host https://api.bencher.example.com \ --name "My Runner"Bencher は新しい Runner をそのキーとともに返します。
{ "uuid": "...", "key": "bencher_runner_..."}キーは一度だけ表示されるため、安全に保管してください。
Runner を起動する際に、このキーを runner バイナリに渡します。
キーを紛失または漏洩した場合は、POST /v0/runners/{runner}/key API でローテーションします。
これにより、以前のキーは直ちに無効化されます。
Spec を作成する
Spec は、Runner が提供するハードウェアを記述します。 オペレーティングシステム、CPU アーキテクチャ、Sandbox の種類、CPU 数、メモリ、ディスク、ネットワークアクセスです。 Job は必要とする Spec を宣言し、Runner はサポートする Spec の Job のみを要求します。
bencher CLI、Specs REST API、
または Bencher Console で Spec を作成します。
bencher spec create \ --host https://api.bencher.example.com \ --name "Intel v1" \ --os linux \ --architecture x86_64 \ --sandbox firecracker \ --cpu 4 \ --memory 51539607552 \ --disk 137438953472サンドボックスなしの Spec を定義するには --sandbox を省略し、
この Spec の Job にネットワークアクセスを許可する場合は --network を渡します。
メモリとディスクはバイト単位で指定します。
Spec の詳細と、Testbed が各 Report で使用された Spec をどのように記録するかについては、
Testbed と Spec を参照してください。
Spec を Runner に割り当てる
Runner Spec は、Spec を Runner に紐付けます。 1 つの Runner は複数の Spec をサポートでき、1 つの Spec は複数の Runner からサポートされ得ます。 Runner は、割り当てられた Spec の Job のみを要求します。
bencher CLI
または Runner Specs REST API で Spec を Runner に追加します。
bencher runner spec add my-runner \ --host https://api.bencher.example.com \ --spec intel-v1後で紐付けを解除するには、DELETE /v0/runners/{runner}/specs/{spec} API を使用します。
Runner を起動する
Runner を作成し、少なくとも 1 つの Spec を割り当てたら、
runner up でハードウェア上の runner バイナリを起動します。
API サーバーのホスト、Runner の UUID またはスラッグ、そして Runner キーを、
フラグまたは環境変数として指定します。
runner up \ --host https://api.bencher.example.com \ --runner my-runner \ --key bencher_runner_...export BENCHER_HOST=https://api.bencher.example.comexport BENCHER_RUNNER=my-runnerexport BENCHER_RUNNER_KEY=bencher_runner_...runner uprunner バイナリは API サーバーへの単一の WebSocket 接続 を開き、
自身の Spec に一致する Job をポーリングし、それぞれを実行して結果を報告します。
接続は複数の Job にわたって開いたままになり、
新しいバージョンが利用可能になると、バイナリは Job の合間に 自身を更新します。
デフォルトでは、Runner は stable 更新チャネルに従い、
バージョン付きリリースへのみ更新します。
canary チャネルは、Bencher Cloud にデプロイされるローリング canary ビルドを追跡します。
サンドボックス化された Job を実行する Runner は root として動かす必要があるため、
上記のコマンドは root ユーザーが実行する場合、
あるいは Runner を root で起動するサービスマネージャー配下での実行を想定しています。
デフォルトでは、Runner は Sandbox のない Spec の Job をすべて拒否します。
Runner にサンドボックスなしの Job をホスト上で直接実行させるには、
--danger-allow-no-sandbox フラグ を付けて起動します。
runner uprunner upRunner を起動し、ベンチマーク Job をポーリングして実行します。 これは セルフホスト型 Runner を運用するために使う、長時間実行コマンドです。 Runner は API サーバーへの単一の WebSocket 接続 を開き、 自身の Spec に一致する Job を要求し、それらを実行して結果を報告します。 Runner は自身のログを 1 行に 1 つのオブジェクトとして JSON 形式で stderr に書き込み、Job の出力はバイト数としてのみ記録します。
runner up [OPTIONS]オプション
--host <HOST>接続先の Bencher API サーバー。 デフォルトでは
https://api.bencher.devが使用されます。BENCHER_HOST環境変数でも設定できます。--runner <RUNNER>運用する Runner の UUID またはスラッグ。
BENCHER_RUNNER環境変数でも設定できます。--key <KEY>Runner が作成された ときに返された Runner 認証キー (
bencher_runner_...)。BENCHER_RUNNER_KEY環境変数でも設定できます。--poll-timeout <POLL_TIMEOUT>Job を待機する際のロングポーリングのタイムアウト (秒)。
1から900の範囲です。 デフォルトでは55が使用されます。--state-dir <STATE_DIR>Runner の永続的な状態ディレクトリ。 絶対パスである必要があります。 サンドボックスを閉じ込める jail はこのディレクトリの下に作成され、 異常終了で残った jail は、各サンドボックス Job の実行前にここから一掃されます。 各 jail はゲストのルートファイルシステム全体と microVM バイナリのコピーを保持し、 Runner は Job を一度に 1 つずつ実行するため、 このディレクトリには jail 1 つ分の実容量が必要です。
--image-cache-sizeを指定すると、そのサイズまで Image キャッシュも保持します。 状態ディレクトリにかかわらず、1 つのホストで実行できる Runner は一度に 1 つだけです。rootとして起動した Runner は実行中ずっとロック/run/bencher/runner.lockを保持し、rootとして起動した 2 つ目の Runner はそのロックを示すエラーを出して即座に終了します。root以外の Runner はロックを開けないため、ロックなしで実行されます。rootとして起動した Runner は、起動時と各サンドボックス Job の前に、Job の途中で強制終了された Runner のサンドボックスなど、/sys/fs/cgroup/bencherの下の cgroup でまだ実行中のプロセスを、その Runner の状態ディレクトリにかかわらずすべて終了させます。 専用のファイルシステムまたはtmpfsマウントがサポートされており、推奨されます。 書き込み負荷をシステムディスクから切り離せます。 作成したばかりのファイルシステムはlost+foundディレクトリを含んでいても受け付けられます。 このファイルシステムはnodevやnoexecでマウントされていてはなりません。/tmp、/dev/shm、/runはよくそのようにマウントされているため、tmpfsを使う場合はこれらのオプションなしで専用にマウントしてください。 状態ディレクトリ自体を、そのようなファイルシステムを指す root 所有のシンボリックリンクにすることもできます。 たとえば/var/lib/bencher-runnerを専用ディスクに向ける形です。 リンクがたどられるのは、リンクを含むディレクトリに書き込めるのが root だけで、 リンクが最終的なターゲットを直接指しており、 そのターゲットが root だけが書き込めるパス上に既に存在する場合に限られます。 ターゲットがまだ存在しないリンクは拒否されるため、先にターゲットを作成してください。 デフォルトでは/var/lib/bencher-runnerが使用されます。 環境変数BENCHER_STATE_DIRでも設定できます。--jail-uid <JAIL_UID>サンドボックスプロセスが移行する非特権ユーザー ID。 デフォルトでは
61016が使用されます。0は指定できません。 このユーザー ID を所有するホスト上のプロセスはサンドボックスにシグナルを送れるため、 ホストが他の用途に割り当てていない ID を指定してください。 環境変数BENCHER_JAIL_UIDでも設定できます。--jail-gid <JAIL_GID>サンドボックスプロセスが移行する非特権グループ ID。 デフォルトでは
61016が使用されます。0は指定できません。 環境変数BENCHER_JAIL_GIDでも設定できます。--danger-allow-no-sandboxSandbox なしでの Job の実行を許可します。 このフラグがない場合、Sandbox を持たない Spec の Job は実行時に拒否されます。 サンドボックスなしの Job はホスト上で直接実行されるため、信頼できるワークロードに対してのみ有効にしてください。
BENCHER_DANGER_ALLOW_NO_SANDBOX環境変数でも設定できます。--sandbox-log-level <SANDBOX_LOG_LEVEL>サンドボックスプロセスのログレベル。 デフォルトでは
warningが使用されます。--no-raid-pauseホスト上の md RAID アレイが再同期、復旧、チェック、修復、または再形成を行っている間も Job を受け付け続けます。 デフォルトでは、Runner は各 Job を要求する前に md アレイを確認し、 いずれかがこれらの処理を実行している間は一時停止します。同期が完了するまで新しい Job を受け付けず、 すでに実行中の Job を停止することはありません。 一時停止中の Runner は接続を維持し、自己更新も引き続き行います。
--no-auto-updateサーバーからの自動更新を無効にします。 デフォルトでは、サーバーが新しいバージョンを提供すると、Runner は Job の合間に自身を更新します。
BENCHER_NO_AUTO_UPDATE環境変数でも設定できます。--update-channel <UPDATE_CHANNEL>自動更新に使用する更新チャネル。
stableまたはcanaryのいずれかです。 デフォルトではstableが使用されます。stableチャネルはバージョン付きリリースへ更新します。canaryチャネルはローリング canary ビルドを追跡し、 このビルドは Bencher Cloud のデプロイで Runner が変更されるたびに再ビルドされます。BENCHER_UPDATE_CHANNEL環境変数でも設定できます。--no-auto-updateと競合します。--max-download-size <MAX_DOWNLOAD_SIZE>自己更新バイナリの最大ダウンロードサイズ (バイト)。 デフォルトでは
500MiB が使用されます。--no-auto-updateと競合します。--image-cache-size <IMAGE_CACHE_SIZE>Runner が Job をまたいで保持する Image blob の最大サイズ (バイト)。 Runner はプルした各 Image の config と layer の blob を
--state-dir配下のblobsに保持するため、 Job は Runner がまだ保持していない blob だけをダウンロードしますが、 Image のマニフェストは毎回レジストリから取得します。 Job の合間に、Runner は残りがこのサイズに収まるまで、最も長く使われていない blob から削除します。 Runner は起動時にこのストアを作成して自身のものにし、それができない場合はディレクトリを示すエラーとともにすぐに終了します。 デフォルト、または0では、Runner は Job をまたいで blob を保持せず、以前に保持していた blob を削除します。 環境変数BENCHER_IMAGE_CACHE_SIZEでも設定できます。--max-output-size <MAX_OUTPUT_SIZE>収集される
stdoutとstderrの最大サイズ (バイト)。 デフォルトでは25MiB が使用されます。--max-file-count <MAX_FILE_COUNT>デコードする出力ファイルの最大数。 デフォルトでは
255が使用されます。--max-symlinks <MAX_SYMLINKS>パス解決時にたどるシンボリックリンクの最大数。 Linux カーネルの
MAXSYMLINKS制限に一致します。 デフォルトでは40が使用されます。 サンドボックスなしモードでのみ使用されます。ホストチューニング
各ベンチマークの前に、
runnerは測定ノイズを低減するためにホストチューニングを適用します。 デフォルトでは、ASLR、NMI ウォッチドッグ、SMT / ハイパースレッディング、ターボブーストを無効にし、 CPU スケーリングガバナーをperformance、swappiness を10、perf_event_paranoidを-1に設定します。 前回の起動以降にrunnerがチューニングしていないホストでは、以下のフラグは、個々の最適化を無効にせず、ホストのデフォルト値のまま維持します。ホストチューニングはホストが再起動するまで持続します。各設定は実行時のみの書き込みであり、
runnerは終了時にそれを元に戻しません。ただし、C ステートの保持はrunnerの終了時に解除されます。 チューニングを行った実行の後では、それ以外の設定をスキップするフラグは次回の再起動から有効になります。それまでは、その設定はチューニングされた値のままであり、runnerは起動時にその値をログに出力します。 共有ホストでは、runnerを削除した後にホストを再起動してください。--no-tuningすべてのホストチューニング最適化を無効にします。
--aslrASLR を無効にしません (デフォルト: ベンチマークでは無効)。
--nmi-watchdogNMI ウォッチドッグを無効にしません (デフォルト: ベンチマークでは無効)。
--smtSMT / ハイパースレッディングを無効にしません (デフォルト: ベンチマークでは無効)。
--turboターボブーストを無効にしません (デフォルト: ベンチマークでは無効)。
--numa-balancing自動 NUMA バランシングを無効にしません (デフォルト: ベンチマークでは無効)。
--timer-migrationタイマーマイグレーションを無効にしません (デフォルト: ベンチマークでは無効)。
--soft-watchdogソフトロックアップウォッチドッグを無効にしません (デフォルト: ベンチマークでは無効)。
--ksmKSM (Kernel Samepage Merging) を無効にしません (デフォルト: ベンチマークでは無効)。
--cstates深い C ステートを無効にしません (デフォルト: ベンチマークでは無効)。
--no-irq-steeringデバイスの IRQ とカーネルのワークキューをハウスキーピングコアに振り向けません。
--no-cpuset-partition分離された cpuset パーティションによってベンチマークコアをスケジューラーから切り離しません。
--swappiness <SWAPPINESS>swappiness の値を設定します。 デフォルトでは
10が使用されます。--governor <GOVERNOR>CPU スケーリングガバナーを設定します。 デフォルトでは
performanceが使用されます。--perf-event-paranoid <PERF_EVENT_PARANOID>perf_event_paranoidの値を設定します。 デフォルトでは-1が使用されます。--thp <THP>ホストの Transparent Hugepage モードを
never、madvise、always、leaveのいずれかに設定します。leaveを指定すると、ホストの現在のモードを維持します。 デフォルトではneverが使用されます。--helpヘルプを表示します。
すべてのオプションについては runner CLI リファレンスを、
サーバーとやり取りされるメッセージについては Runner プロトコル リファレンスを参照してください。
ホストのメンテナンス
Runner とそのホストのメンテナンス(パッケージのアップグレードや RAID スクラブなど)は交代で実行されるため、メンテナンスが Job の実行中に走ることはありません。
交代は /run/bencher を通じて行われます。これは root として起動した Runner が root 専用に作成するディレクトリです。
- Job ロック、
/run/bencher/job.lock。 Runner は Job を要求する前にこれを取得し、そのポーリングが Job なしで終わるか、届いた Job が終わるまで保持します。 メンテナンスはこのロックを待つため、Job と Job の間にしか始まりません。 また、ロックが保持されているのを見つけた Runner は、ロックが空くまで Job を受け付けません。 - メンテナンスマーカー、
/run/bencher/maintenanceまたは/run/bencher/maintenance.<name>。 メンテナンスはロックを待つ前に自分のマーカーを作成し、完了したら削除します。 マーカーが存在する間、Runner は Job を要求せずロックを空けておくため、 待機中のメンテナンスは Runner の現在のポーリング、またはそのポーリングで届いた Job が終わり次第始まります。
メンテナンスを待つ間、Runner は一時停止しています。接続は維持され、自己更新も引き続き行います。
runner run も Job ロックを待ち、マーカーが存在する間や md アレイが同期している間は警告を出しつつ実行します。
root ではない Runner は Job ロックを開くこともマーカーを見ることもできないため、それらなしで Job を受け付けます。
systemd では、ドロップインによってメンテナンスユニットに順番を待たせます。
たとえば /etc/systemd/system/fstrim.service.d/zz-bencher-quiet.conf は、ユニット自身のコマンドを flock -F で包みます。
空の ExecStart= はそのコマンドを消去するため、次の行でそれを正確に繰り返す必要があります。
[Service]ExecStartPre=+/usr/bin/install -d -m 0700 /run/bencherExecStartPre=+/usr/bin/touch /run/bencher/maintenance.%nOpenFile=/dev/nullExecStart=ExecStart=/usr/bin/flock -F /run/bencher/job.lock /sbin/fstrim --listed-in /etc/fstab:/proc/self/mountinfo --verbose --quiet-unsupportedExecStopPost=+/bin/sh -c '/usr/bin/busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager PreparingForShutdown | /usr/bin/grep -q true || /usr/bin/rm -f /run/bencher/maintenance.%n'TimeoutStartSec=infinityOpenFile=/dev/null がファイルディスクリプタ 3 を占めるため、apt.systemd.daily のようにコマンドがディスクリプタ 3 を開き直しても、ロックは保持されたままです。
ホストがシャットダウンの準備をしている間、ExecStopPost= はマーカーを残すため、再起動で /run が空になるまで Runner は Job を受け付けません。
Runner をドレインする
Runner をドレインするには、root として単純なマーカーを作成します。
touch /run/bencher/maintenanceRunner は現在のポーリング(最大 --poll-timeout 秒)と、実行中の Job またはそのポーリングで届いた Job を終えた後、マーカーがなくなるまで次の Job を受け付けません。
rm /run/bencher/maintenance/run は起動時に空になるため、再起動でもマーカーは削除されます。
セルフホスト型 Runner のワークフロー
Runner が接続されると、他の Bare Metal Runner と同じ方法でベンチマークを送信します。
Image をビルドしてプッシュし、一致する Spec で bencher run --image を実行します。
以下の図は、Runner の登録から Job の実行までの全体の流れを示しています。