Gridを始める

Selenium Gridの導入方法

クイックスタート

  1. 事前条件

  2. Grid の起動

    • java -jar selenium-server-<version>.jar standalone
  3. あなたの WebDriver テストの対象を http://localhost:4444 に向ける

  4. (必要があれば) ブラウザでhttp://localhost:4444を開いて実行中のテストや利用可能な capabilities を確認する。

さらにオプションを知りたい場合は以降のセクションに進んでください。

Grid コンポーネントロール

Grid は 6 つの異なるコンポーネントで構成され、様々な方法でデプロイすることができます。

必要に応じて、それぞれ個別に起動する(分散)か、ハブ&ノードのグループに分けるか、 全てを一つのマシンで起動する(スタンドアロン)かを選べます。

スタンドアロン

スタンドアロンは全ての Gridコンポーネントを 1 つに連結します。 スタンドアロンモードはシングルプロセスで動き、Grid の全機能を利用することができます。 スタンドアロンは単一のマシン上でのみ動かすことができます。

スタンドアロンは Selenium Grid を起動する最も簡単な方法でもあります。 デフォルトではサーバーはhttp://localhost:4444RemoteWebDriver リクエストをリッスンします。 サーバーはデフォルトでシステムパス上の利用可能なドライバーを検出します。

java -jar selenium-server-<version>.jar standalone

スタンドアロンで Grid のを起動したら、WebDriver テストの対象をhttp://localhost:4444に向けてください。

スタンドアロンの一般的なユースケースは:

  • RemoteWebDriver を使用したローカルでの開発やデバッグ
  • コードをプッシュする前の簡易なテスト実行
  • CI/CD 向けの Grid のセットアップ(GitHub Actions, Jenkins など)

ハブ&ノード

ハブ&ノードは最も利用されているロールです。その理由は:

  • 様々なマシンを Grid に統合できます
    • 様々な OS やブラウザーバージョンを持つマシンなど
  • WebDriver テストのエントリーポイントを持っています
  • Grid を停止せずにキャパシティのスケールアップ・ダウンが可能です

ハブ

ハブは以下のコンポーネントで構成されています。 ルーター、ディストリビューター、セッションマップ、新規セッションキュー、イベントバス。

java -jar selenium-server-<version>.jar hub

デフォルトでは、サーバーはhttp://localhost:4444にて RemoteWebDriver リクエストを待ち受けます。

ノード

ノードは起動時にシステムのパス が通っている利用可能なドライバーを検出します。

次のコマンドはノードハブと同じマシン上で動作していることを前提としています。

java -jar selenium-server-<version>.jar node
同一マシン上での複数ノード

ノード 1

java -jar selenium-server-<version>.jar node --port 5555

ノード 2

java -jar selenium-server-<version>.jar node --port 6666
異なるマシンでノードとハブを動かす

ハブノードは HTTP とイベントバスを介して通信します (イベントバスハブの一部として存在します)。 ノードイベントバスを通じてメッセージを送信し、登録処理を開始します。 ハブがメッセージを受け取り、ノードの存在を確かめるため HTTP を使ってノードにアクセスします。

ハブがデフォルトのポートを使用していれば、 --hub フラグでノードを登録することができます。

java -jar selenium-server-<version>.jar node --hub http://<hub-ip>:4444

ハブがデフォルトのポートを使用していない場合、--publish-events--subscribe-events のフラグが必要です。

例えばハブ8886 8887 8888 ポートを利用している場合、

java -jar selenium-server-<version>.jar hub --publish-events tcp://<hub-ip>:8886 --subscribe-events tcp://<hub-ip>:8887 --port 8888

ノードはこれらのポートを登録する際に使用します。

java -jar selenium-server-<version>.jar node --publish-events tcp://<hub-ip>:8886 --subscribe-events tcp://<hub-ip>:8887

分散

分散 Grid を利用すると、各コンポーネントは別々に起動され異なるマシン上で動作します。

  1. イベントバスは Grid コンポーネント間での内部通信を可能にします。

デフォルトポートは 4442, 4443, 5557 です。

java -jar selenium-server-<version>.jar event-bus --publish-events tcp://<event-bus-ip>:4442 --subscribe-events tcp://<event-bus-ip>:4443 --port 5557
  1. 新規セッションキューは新規セッションリクエストをキューに積み、ディストリビューターがリクエストを取得できるようにします。

デフォルトポートは 5559 です。

java -jar selenium-server-<version>.jar sessionqueue --port 5559
  1. セッションマップはセッション ID とそのセッションが実行中のノードのマップを持ちます。

デフォルトのセッションマップのポートは 5556 です。 セッションマップイベントバスと通信します。

java -jar selenium-server-<version>.jar sessions --publish-events tcp://<event-bus-ip>:4442 --subscribe-events tcp://<event-bus-ip>:4443 --port 5556
  1. ディストリビューター新規セッションキューに新規セッションリクエストを問い合わせ、 capabilities がマッチするノードにアサインします。ノードは、ハブ&ノード構成の Grid におけるハブの登録と同じように、ディストリビューターに登録します。

デフォルトのディストリビューターのポートは 5553 です。 ディストリビューター新規セッションキューセッションマップイベントバスノードと通信します。

java -jar selenium-server-<version>.jar distributor --publish-events tcp://<event-bus-ip>:4442 --subscribe-events tcp://<event-bus-ip>:4443 --sessions http://<sessions-ip>:5556 --sessionqueue http://<new-session-queue-ip>:5559 --port 5553 --bind-bus false
  1. ルーター新規セッションリクエストをキューに、既存セッションのリクエストをそのセッションが実行中のノードに転送します。

デフォルトのルーターのポートは 4444 です。 ルーター新規セッションキューセッションマップディストリビューターと通信します。

java -jar selenium-server-<version>.jar router --sessions http://<sessions-ip>:5556 --distributor http://<distributor-ip>:5553 --sessionqueue http://<new-session-queue-ip>:5559 --port 4444
  1. ノード

デフォルトのノードのポートは 5555 です。

java -jar selenium-server-<version>.jar node --publish-events tcp://<event-bus-ip>:4442 --subscribe-events tcp://<event-bus-ip>:4443

テストメタデータ

テストにメタデータを追加して、GraphQL 経由で使用するか、Selenium Grid UI 経由でその一部( se:name など) を可視化します。

メタデータは capability にse:プリフィックスをつけることで追加できます。 Java での簡単な例を紹介します。

ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setCapability("browserVersion", "100");
chromeOptions.setCapability("platformName", "Windows");
// Showing a test name instead of the session id in the Grid UI
chromeOptions.setCapability("se:name", "My simple test");
// Other type of metadata can be seen in the Grid UI by clicking on the
// session info or via GraphQL
chromeOptions.setCapability("se:sampleMetadata", "Sample metadata value");
WebDriver driver = new RemoteWebDriver(new URL("http://gridUrl:4444"), chromeOptions);
driver.get("http://www.google.com");
driver.quit();

Selenium Grid のクエリ

Grid 起動後、ステータスを問い合わせる方法は、 Grid UI と API 呼び出しの主に 2 通りあります。

Grid UI は、お好みのブラウザでhttp://localhost:4444 にアクセスすることで見られます。

API 呼び出しはhttp://localhost:4444/statusのエンドポイントか、 GraphQLが利用できます。

このページで紹介するコマンドの例は、わかりやすくするために コンポーネントがローカルで動作していると仮定しています。 より詳細な例と使用方法はコンポーネントの章を参照してください。

Java 11 の HTTP クライアントを利用する

Selenium v4.5

デフォルトでは Grid はAsyncHttpClientを使用します。 AsyncHttpClient は Netty を使ったオープンソースのライブラリで、非同期での HTTP リクエストを実現します。 さらに WebSocket をサポートするため Grid に適しています。

しかし、AsyncHttpClient は 2021 年からあまり活発にメンテナンスされていません。 そして Java 11+ではビルトインの HTTP と WebSocket のクライアントを提供しています。 現在 Selenium はサポートする最小バージョンを Java11 にアップグレードする計画をしていますが、 それにはかなりの労力が必要です。メジャーリリースに合わせることはユーザー体験にとって重要です。

Java11 のクライアントを利用するにはselenium-http-jdk-clientjar ファイルをダウンロードし、 --extフラグで Grid の jar のクラスパスに通す必要があります。

jar ファイルはrepo1.maven.orgから直接ダウンロードできます。 Grid を起動する方法は以下の通りです:

java -Dwebdriver.http.factory=jdk-http-client -jar selenium-server-<version>.jar --ext selenium-http-jdk-client-<version>.jar standalone

selenium-http-jdk-clientをダウンロードする別の方法としてCoursierを使う方法があります。

java -Dwebdriver.http.factory=jdk-http-client -jar selenium-server-<version>.jar --ext $(coursier fetch -p org.seleniumhq.selenium:selenium-http-jdk-client:<version>) standalone

ハブ&ノードか分散モードで動かす場合、-Dwebdriver.http.factory=jdk-http-client--extフラグの設定が各コンポーネントに必要になります。

Grid サイズ

Grid ロールの選択は、どのような OS やブラウザをサポートする必要があるかによって決まります。 どの OS、ブラウザをサポートするか、どのくらいの並列セッションを実行するか、マシンの数とそれらの性能(CPU、RAM)に依存します。

セッションを並列で作成するのは、ディストリビューターが利用可能なプロセッサーに依存します。たとえば、 マシンに 4 つの CPU がある場合、ディストリビューターは同時に最大 4 つのセッションしか作成できません。

デフォルトでは、ノードがサポートする同時セッションの最大数は、利用可能な CPU の数によって制限されます。 たとえば、ノードのマシンに 8CPU がある場合、同時に最大 8 つのブラウザセッションを実行できます(ただし、Safari は常に 1 つです)。 また各ブラウザセッションは約 1GB の RAM を使用することが期待されます。

一般的にノードはできるだけ小さくすることが推奨されます。32CPU と 32GB の RAM を持つマシンで 32 の同時ブラウザセッションを実行するよりも、 32 の小さな プロセスをよりよく分離するために、 32 の小さなノードを持つことが推奨されます。これによって、もしノードに障害が発生しても、分離されて処理されます。 Docker はこの方法を実現するための優れたツールです。

デフォルト値(ブラウザあたり 1CPU/1GB RAM)は推奨値であり、あなたの用途に沿わない可能性があることに注意してください。 この値は参考値としての推奨であり、継続的にパフォーマンスを測定することで、あなたの環境にとって理想的な値を見つけることができるでしょう。

Grid のサイズは、サポートされる同時セッションの数と、ノードの数に関連しており、 万能なサイズというものはありません。以下のサイズは概算で、環境が違えば変わる可能性があります。 例えば、120 台のノードを持つハブ&ノードの場合、ハブが十分なリソースを持っていればうまく機能するかもしれません。 また、この数値は確定したものではありません。フィードバックをお待ちしています。

Small

5 台以下のノードで、スタンドアロンハブ&ノード

Middle

6〜60 台のノードで、ハブ&ノード

Large

60〜100 台のノードで、ハブ&ノード、あるいは 100 台以上のノード分散

警告

Grid を保護しないと、以下のような問題が発生する可能性があります。

  • Grid インフラストラクチャへのオープンアクセスを許容してしまう。
  • サードパーティが内部 Web アプリケーションやファイルにアクセスすることを許可してしまう。
  • サードパーティにカスタムバイナリの実行を許可してしまう。

Detectify のブログで公開されてしまった Grid が どのように悪用されるかを紹介しています: Don’t Leave your Grid Wide Open

参考文献