Medium.comの記事の翻訳、 パート1 、 パート2を紹介します。 記事の最初の部分には主にこの投稿ですでに述べられている内容が含まれているため、2番目の部分のみの翻訳を引用します。
![](https://habrastorage.org/files/7f4/8ce/537/7f48ce537b054eec9e98635970272980.jpeg)
重量を減らしてコンテナに移動する
記事の前半では、コードを記述せずにスケーラブルなSeleniumクラスターを構築できる簡単なアプローチについて説明しました。 このパートでは、Seleniumを使用する際のより微妙な問題を見ていきます。
- 標準のSelenium Hubを使用して簡単にスケーラブルな作業ノードを作成する方法
- コンテナでほとんどのブラウザを起動することが可能であり、必要な理由とその方法
- このためのオープンソースツールは何ですか
作業ノード内の内容
前半で説明したすべての新しいツールは、実際にはユーザーのリクエストを実際のSeleniumのハブとノードにリダイレクトするスマートな軽量プロキシです。 少し考えると、疑問が生じます。
- ハードウェアリソースを効率的に消費して適切に拡張するために、ハブとノードを整理する方法
- 使用するオペレーティングシステム
- どのプログラムをインストールする必要がありますか?
- モニターなしで作業できますか?
1つの方法は、1つのSeleniumハブと異なるブラウザーの多くのノードでハードウェアを使用することです。 それは合理的に見えますが、本当に不快です:
![](https://habrastorage.org/files/ad3/fd9/bb6/ad3fd9bb671b4f0eb63bd261bcaaa3bb.png)
- 言われたように、ロードされたノードの数が多いSeleniumハブの動作は非常に遅くなります。 本当の理由については定かではありませんが、実践はそれを示しています。 悪夢を見たくないのなら、夜にセレニウムの出所を読まないように。 したがって、同じハブで多数のSeleniumノードを使用することはできません。 1つのハブと少数のノードのみを使用することに変わりはありません。 鉄を効果的に使用するには、ハブごとのコアの総数を減らす必要があります。これは、クラウドに移行する正当な理由です。 たとえば、私たちの作業グリッドは、2つのコアと4 GBのメモリを備えた小さな仮想マシンを長い間使用しています。
- 1つのブラウザーの異なるバージョンを簡単な方法で(たとえば、パッケージから)インストールする方法は不明です。
- 1つのバージョンで使用可能なブラウザーの総数を考慮することがいかに簡単かは明らかではありません。
- Seleniumノードの異なるバージョンは、ブラウザーの異なるバージョンと互換性があります。 新しいSeleniumノードは古いブラウザーをサポートしない場合があります。
ハブごとに同じ数のノードを持つ最も簡単な方法は、同じ仮想マシン内で実行することです。 各ブラウザーバージョンが個別の仮想マシンである場合、使用可能なブラウザーの総数をカウントすることは、小学校のタスクになります。 互換性のあるバージョンのノードとブラウザーを含む仮想マシンを簡単に追加および削除できます。 Seleniumクラスターを、ブラウザーの各バージョンが常に利用可能な量でクラウドにインストールする場合、このアプローチをお勧めします。
![](https://habrastorage.org/files/ba4/159/4e8/ba41594e8a904132b9a161444683c585.png)
すべてが機能するように、Seleniumハブとノード以外に仮想マシン内に他に何がありますか?
- まず、可能な限りプライマリオペレーティングシステムとしてLinuxを使用することをお勧めします。 Linuxを使用すると、ブラウザーのニーズの80%をカバーできます。 カバーされていないものをリストする方が簡単です:
- Internet ExplorerおよびMicrosoft Edge。 これらのブラウザーはWindowsでのみ機能し、別の記事に値します。 世界には悲しい物語はありません...
- デスクトップSafari 誰でもそれを使用しますか? Seleniumは、このブラウザーのサポートがかなり不十分です。
- iOSおよびAppleの携帯電話。 これらのデバイスを使用するには、MacMiniやAppiumなどのAppleのハードウェアを使用する必要があります。
- Seleniumを実行するには、Java(JDKまたはJRE)をインストールし、必要なバージョンのSeleniumをJARアーカイブとしてダウンロードする必要があります。
仮想マシンにはモニターがないため、ディスプレイをエミュレートする特別なバージョンのXサーバーでSeleniumを実行する必要があります。 この実装はXvfbと呼ばれます。 次のように始まります。
xvfb-run -l -a -s '-screen 0 1600x1200x24 -noreset' \ java -jar /path/to/selenium-server-standalone.jar -role node <... >
XvfbはSeleniumノードプロセスにのみ必要であることに注意してください。
- Microsoft True Typeフォントなどの追加のフォントパッケージをインストールすることもできます 。
- テストでサウンドを再生する必要がある場合は、サウンドカードのサポートを構成する必要があります。 Ubuntuの場合、これは次のようになります。
#!/bin/bash apt-get -y install linux-sound-base libasound2-dev alsa-utils alsa-oss apt-get -y install --reinstall linux-image-extra-`uname -r` modprobe snd-dummy if ! grep -Fxq "snd-dummy" /etc/modules; then echo "snd-dummy" >> /etc/modules fi adduser $(whoami) audio
薄く成長する
お気づきかもしれませんが、SeleniumはJavaアプリケーションです。 Seleniumを実行するには、Java仮想マシン(JVM)をインストールする必要があります。 JREと呼ばれる最小のJavaインストールパッケージのサイズは約50メガバイトです。 最新のSelenium JARバージョン3.0.1では、さらに20メガバイトが追加されます。 次に、オペレーティングシステムのサイズ、目的のフォント、ブラウザ自体のサイズを追加すると、数百メガバイトに簡単に到達できます。 また、ハードドライブは安価になりましたが、さらに改善することができます。 Seleniumバージョン2.0および3.0は、Selenium Webdriverとも呼ばれます。 これは、さまざまなブラウザーのサポートがWebドライバーと呼ばれる別個のアプリケーションを使用して実装されているという事実によるものです。
仕組みは次のとおりです。
- ブラウザ開発者は、必要に応じて製品を作成できます。 Seleniumでブラウザをサポートするには、Selenium Server自体と同じAPIを提供し、JSONWireプロトコルをサポートするWebサーバーアプリケーションを提供する必要があります。 このアプリケーションは、ブラウザプロセスを開始し、仕様に従ってSeleniumコマンドを実行し、要求に応じてブラウザを停止できる必要があります。 ドライバとブラウザの相互作用の詳細は、開発者の裁量で実装できます。 唯一の要件は、同じSelenium APIのサポートです。 たとえば、ChromeにはChromedriverがあり 、Opera BlinkはOperaDriverなどを提供します。
- Seleniumをインストールするときは、ドライバーアプリケーションへのパスを指定するだけです。
- Seleniumにブラウザをリクエストすると、実際にドライバプロセスが開始され、すべてのリクエストがドライバにプロキシされます。 ドライバーは残りの作業を行います。 必要なポートでドライバープロセスを手動で開始し、テストをそのポートに向けると、同じ結果が得られます。
これを理解した今、疑問が生じます:単純なプロキシに数百メガバイトを費やすのは高すぎるのでしょうか? 1年前、Seleniumで最も一般的に使用されているブラウザであるFirefox用のドライバーアプリケーションがなかったため、答えは間違いなくノーでした。 Seleniumの役割は、Firefoxを起動し、Firefoxに特別な拡張機能をロードし、この拡張機能によって開かれたポートにリクエストをプロキシすることでした。 過去1年間で状況は変わりました。 Firefox 48.0以降、Seleniumは別のバイナリドライバーGeckodriverを使用してブラウザーと対話します。 これは、ほとんどのデスクトップブラウザで、Selenium Serverとプロキシリクエストをドライバに直接完全に削除できることを意味します。
コンテナに移動します
前のセクションでは、クラウド内の仮想マシンを使用してSeleniumクラスターを構築する方法について説明しました。 このアプローチでは、仮想マシンは常に稼働しており、常にお金を費やしています。 さらに、各バージョンで使用可能なブラウザーの総数は制限されており、負荷のピーク時に使用可能なブラウザーが完全に使い果たされる可能性があります。 現在の負荷に応じて仮想マシンのプールを起動およびウォームアップし、常にブラウザーを使用できるようにする、特許取得済みの複雑なソリューションについても聞いたことがあります。 それは機能しますが、もっと良くできますか? ハイパーバイザー仮想化の主な問題は速度です。 新しい仮想マシンの起動には数分かかる場合があります。 しかし、少し考えてみましょう-各ブラウザに個別のオペレーティングシステムが必要ですか? -いいえ、ディスクとネットワークを単純に分離するだけで済みます。 これが、コンテナ仮想化が重要になっている理由です。 現時点では、コンテナーは主にLinuxでのみ動作しますが、先ほど言ったように、Linuxは最も人気のあるブラウザーの80%をカバーしています。 ブラウザを備えたコンテナは数秒で起動し、さらに速く停止します。
コンテナの中には何がありますか? -仮想マシン内とほぼ同じ:ブラウザー自体、フォント、Xvfb。 Firefoxの古いバージョン(<48.0)では、JavaとSelenium Serverをインストールする必要がありますが、Chrome、Opera、およびFirefoxの新しいバージョンでは、ドライバーアプリケーションをメインコンテナープロセスとして使用できます。 軽量のLinuxディストリビューション(Alpineなど)を使用している場合、非常に小さく軽量なコンテナーを入手できます。
セレノイド
現在、最も人気があり、有名なコンテナプラットフォームはDockerです。 Selenium開発者は、Seleniumをスタンドアロンで実行するための既製のDockerコンテナのセット、またはDockerのグリッドモードを提供します。 そのようなイメージのクラスターを開始するには、コンテナーを手動で、またはDocker Composeなどのツールを使用して開始および停止する必要があります。 このアプローチは、パッケージからSeleniumをインストールするよりもすでにはるかに優れていますが、次の動作を持つサーバーがあればさらに優れています。
- 管理者は、通常のSeleniumハブの代わりにサーバーデーモンを起動します。
- デーモンは、(設定から)たとえば、Firefox 48.0を起動するにはコンテナXを、Chrome 53の場合はコンテナYをダウンロードして実行する必要があることを認識しています。
- ユーザーは通常の方法でSeleniumセッションを要求しますが、この新しいデーモンを使用します。
- デーモンは、目的の機能を分析し、必要なコンテナーを起動してから、メインコンテナープロセス(SeleniumサーバーまたはWebドライバー)に要求をプロキシします。
私たちはそのような悪魔を作りました...そしてさらにもっと。
Seleniumサーバーを大規模に使用してきた長年にわたって、要求の単純なプロキシにJVMとシックSelenium JARを使用するのは非常に非効率的であることがわかりました。 そのため、より軽量なテクノロジーを探していました。 私たちの選択は、Golangとしても知られるGoプログラミング言語に限定されます。 Goがなぜ私たちの目的に適しているのですか?
- 静的リンク。 コンパイルの結果は1つのファイル-バイナリであり、サーバーにコピーしてすぐに実行できます。 実行するには、依存関係やJVM for Javaなどの追加プログラムをインストールする必要はありません。
- クロスコンパイル。 同じコンパイラを備えた同じマシン上で、異なるオペレーティングシステムのバイナリを収集できます。
- 豊富な標準ライブラリ。 私たちにとって最も重要なのは、リバースプロキシとHTTP / 2ボックスからのサポートです。
- 開発者の大規模なコミュニティ。 この言語はすでに、特定のクラスのタスクで最も人気のある言語の1つになりつつあります。
- IDEで十分にサポートされています。 Go for IntellijIDEA用の優れたプラグインと、同じ開発者による完全なGoglang IDEのアルファ版があります。
上記の悪魔の良い名前を思いつきませんでした。 したがって、単にSelenoidと呼びました 。 Selenoidを試すには、3つの簡単な手順に従う必要があります。
- ブラウザのバージョンごとに実行するコンテナに関する情報を含むJSONファイルを作成します。
{ "firefox": { "default": "latest", "versions": { "49.0": { "image": "selenoid/firefox:49.0", "port": "4444" }, "latest": { "image": "selenoid/firefox:latest", "port": "4444" } } }, "chrome": { "default": "54.0", "versions": { "54.0": { "image": "selenoid/chrome:54.0", "port": "4444" } } } }
GridrouterのXMLファイルと同様に、使用可能なブラウザーバージョンのリストがリストされます。 Selenoidは同じマシン上またはDocker APIを介してコンテナを実行するため、ホスト名とリージョンを指定する必要はありません。 ブラウザのバージョンごとに、コンテナの名前、バージョン、およびコンテナのメインプロセスをリッスンするポートを指定する必要があります。
- Selenoidを起動します。
$ selenoid -limit 10 -conf /etc/selenoid/browsers.json
デフォルトでは、Selenoidは通常のSeleniumハブのようにポート4444で起動します。
- 通常のSeleniumハブであるかのように、Selenoidホストでテストを実行します。
私たちの実験では、内部に標準のSeleniumサーバーがあるコンテナでも数秒で起動することが示されています。 代わりに、ディスクとメモリの保証された状態を取得します。 ブラウザは常に、クリーンなオペレーティングシステムにインストールした後と同じ状態になります。 さらに、Dockerイメージとして保存された、サポートされているブラウザーの同じセットを持つホストの大規模なクラスターにSelenoidをインストールできます。 これにより、ブラウザーの使用状況に基づいて自動的にスケーリングされる大規模なSeleniumクラスターが提供されます。 たとえば、現在のユーザーリクエストにより多くのChromeが必要な場合、より多くのコンテナが自動的に起動します。 Chromeに対する要求がない場合、Chromeコンテナーは停止し、無料のホストを他のブラウザーに使用できます。
クラスター全体の負荷分散を改善するために、Selenoidはホスト上の同時セッションの合計数を制限し、制限を超えるすべての要求をキューに入れます。 キューからのリクエストは、同じホストエンドで以前のセッションとして処理されます。
ただし、Selenoidを使用すると、コンテナだけでなくそれ以上の実行が可能になります。 また、オンデマンドWebドライバープロセスを実行する方法も知っています。 この機能の主な用途は、Selenium ServerをWindowsに置き換えることです。 この場合、SelenoidはIEDriverServerプロセスを開始します。これにより、メモリが節約され、Selenium自体のプロキシエラーが回避されます。
Go Grid Router(ggrとも呼ばれる)
元のGridRouterはJavaアプリケーションであることを覚えているかもしれません。 Goでこのプロキシの軽量な実装をゼロから作成し、単にGo Grid Router (またはggr)と名付けました。 古いバージョンと比較した新しいバージョンの利点は何ですか?
- 生産性の向上。 少なくとも25%以上のリクエストに対応できます。
- より少ないメモリ消費。 150 rpsの負荷では、100〜200メガバイトのメモリしか消費せず、この数値は変わりません。
- クライアントの切断の追跡。 クライアントが(タイムアウトなどにより)切断した場合、GridRouterのJavaバージョンはホストの繰り返しを続け、セッションを作成しようとします。 これにより、ネットワークに不要なパケットが詰まり、多くのハブが使用できなくなったときにGridRouterのパフォーマンスが低下します。 Goの新しい実装は、クライアントが切断されるとすぐにブラウザーを取得しようとしなくなります。
- 接続を失うことなくサーバーを再起動します(グレースフルリスタート)。 サーバーがDockerコンテナーの外部で使用されている場合、プロセスにSIGUSR2シグナルを送信することにより、接続を失うことなくサーバーを再起動できます。
- リクエストに応じてクォータをリロードします。 バランサーの背後でGridRouterの複数のインスタンスを使用する場合、クォータを同時に更新することが重要です。 新しいホストがクォータXMLファイルに追加され、稼働中のSeleniumクラスターでクォータが同時に更新されない場合、1つのGridRouterヘッドが既に新しいホストを認識してリクエストをそこにリダイレクトし、他のホストがこれらのホストを認識せず、404エラーを返す状況が発生する場合がありますGoでの実装は、Javaバージョンで発生するように、自動的にではなく、SIGHUPシグナルでクォータをリロードします。 この機能は、DockerでもDockerなしでも機能します。
- 暗号化されたパスワード。 Ggrは、Apache htpasswd形式のテキストファイルを使用して、ログインとパスワードを保存します。 ログインはクリアテキストで保存され、パスワードは暗号化されます。
- 実行可能ファイルのサイズが小さい。 わずか6メガバイト。 Javaのインストールは不要です。 Dockerにインストールした場合、Alpine Linuxベースのコンテナーは11メガバイトしか必要としません。
Selenoidと組み合わせて、スケーラブルで信頼性の高いSeleniumクラスターを作成できます。
おわりに
このパートでは、最新のSeleniumクラスターを編成するために使用できる最新のテクノロジーについて説明しました。
- Seleniumがコンテナーにうまくパックされて実行される理由
- コンテナの中にあるべきもの
- コンテナ内でSeleniumを操作するためのオープンソースツールは何ですか
参照資料
結論として、記事に記載されている製品へのリンクは1か所で収集されます。