【IaCで作るselenium環境】03_Ggrを構築する

直近の関連エントリ

――――――――――――――――――――――――――――――――――

こんにちは。SHIFTのスクラムマスター・テスト自動化エンジニアの石丸です。

前回、簡単にSelenoidを試すことのできる環境構築までお話ししました。
今回は、実行時に少しだけ工夫を入れます。


■今回のテーマ


今回のテーマは「Ggr(Go Grid Router)」です。

こちらを使えば、複数のSelenoid環境を実行できるようになります。

■前提


・DockerDesktop Version 2.3.0.3(記事記述現時点での最新)
・第1回、第2回の環境が整っていること
・windows環境での構築
・自マシン以外にPもう一台のselenoid環境準備

■前回のおさらい


前回の最後はこんな感じでした。

今回の構成_02

テストコードのみDataVolumeとして外部参照し、それ以外は全てコンテナになっている状態です。

■Selenoidの運用課題


前回まででオードソックスなSelenoid環境(クライアント環境と実行環境)は整ったと思います。

さて、ひとつのSelenoidコンテナで運用してゆくとかなり早い段階でリソースの問題に直面します。


例えば並列実行を行おうとした場合、私のマシンでは3コンテナを実行するだけで、Dockerに割り当てたCPUが天井に張り付いてしまいました。

というわけで、Selenoidコンテナを複数構築することになるのですが、その際に使用するのがGgrです。Ggrに複数のSelenoidコンテナを紐づけておけば、同一URLで自動的にロードバランシングしてくれます。


■Ggrの構成


今回はこのような構成を目指します。

今回の構成_03


1. テスト実行環境はSelenoidとは無関係なので、Selenoidと分離します。(ローカルPC1)

2. スケールしたいのはあくまでクライアントマシンコンテナなので、監視系コンテナを分離します。(ローカルPC2のSelenoid-UI)

3. クライアントマシン環境が独立しました。(ローカルPC3)
クライアントマシンが1つだと厳しい場合は同じ環境を増やしていきます。(ローカルPC4)。

4. 最後に実行環境とクライアントマシン環境を繋ぐGgrを配置します。(ローカルPC2のGgr、Ggr-UI)


Ggr-UI

クライアントマシン環境が分散するとSelenoid-UIひとつでは監視カバーできません。
これを担保するのがGgr-UIです。

が、Ggr-UIにはGUIがないです。
これを既存のSelenoid-UIでカバーします。

Ggr-UIがListenしたSelenoidの情報をSelenoid-UIにバイパスすると、Ggr経由で接続されているSelenoid全てがSelenoid-UI上で表示・確認できるようになります。

まずは監視用コンテナのdocker-compose.ymlと、クライアントマシン用docker-compose.ymlを以下のように分けます。

フォルダ構成

すみません。今回はクライアントマシン環境を多数台用意することができず、1つは自PC(つまりローカルPC1)となります。
テスト実行環境、監視環境、クライアントマシン環境の1つはローカルPC1相乗りとなります。。ごめんなさい。

・ローカルPC1、2、3

※mavenでのテスト実行環境は既存の環境を使用するので割愛


ggr
 |ーggr
 |  |ーdocker-compose.yml
 |  |ーDockerfile_ggr
 |  |ーtext.xml
 |
 |ーselenoid
    |ーdocker-compose.yml
    |ーconfig
        |ーbrowsers.json


・ローカルPC4


selenoid
 |ーdocker-compose.yml
 |ーconfig
    |ーbrowsers.json


というわけで今回は、Ggrの動作が最低限確認できる以下の構成で妥協します。

今回の構成_03_妥協版

■Ggrの準備


準備に5つ手順があります。


手順1:クライアントマシン用docker-compose

例示の格納フォルダ
c:/tmp/docker/ggr/selenoid

docker-compose.yml

version: "3.7"
services:
 selenoid:
   container_name: selenoid
   image: "aerokube/selenoid:latest-release"
   network_mode: bridge
   restart: always
   ports:
     - "4444:4444"
   volumes:
     - "./config:/etc/selenoid"
     - "/var/run/docker.sock:/var/run/docker.sock"
     - "./video/:/opt/selenoid/video/"
     - "./logs/:/opt/selenoid/logs/"
   environment:
     - OVERRIDE_VIDEO_OUTPUT_DIR=/c/tmp/docker/ggr/selenoid/video
   command: >
     -conf /etc/selenoid/browsers.json
     -video-output-dir /opt/selenoid/video
     -log-output-dir /opt/selenoid/logs
   healthcheck:
     test: ["CMD-SHELL", "stat /opt/selenoid/logs/ || exit 1"]
     interval: 10s
     timeout: 10s
     retries: 3
     start_period: 30s
 videorecorder:
   container_name: video-recorder
   image: selenoid/video-recorder:latest-release
   restart: always
   healthcheck:
     test: ["CMD-SHELL", "stat /var/ || exit 1"]
     interval: 10s
     timeout: 10s
     retries: 3
     start_period: 30

Selenoid-UIが無くなってスッキリしました。
また8083ポートではなく4444ポートに変えます。


手順2:監視用docker-compose

例示の格納フォルダ
c:/tmp/docker/ggr/ggr

docker-compose.yml

version: "3.7"
services:
 ggr:
   build:
     context: .
     dockerfile: Dockerfile_ggr
   image: aerokube/ggr
   container_name: ggr
   restart: unless-stopped
   ports:
     - "8083:4444"
   volumes:
     - ggr:/etc/grid-router:ro
   healthcheck:
     test: ["CMD-SHELL", "stat /etc/grid-router/users.htpasswd || exit 1"]
     interval: 10s
     timeout: 10s
     retries: 3
     start_period: 30s
 ggr-ui:
   restart: always
   image: aerokube/ggr-ui
   container_name: ggr-ui
   network_mode: bridge
   ports:
     - "8888:8888"
   volumes:
     - ggr-ui:/etc/grid-router/quota:ro
   healthcheck:
     test: ["CMD-SHELL", "stat /etc/grid-router/quota/test.xml || exit 1"]
     interval: 10s
     timeout: 10s
     retries: 3
     start_period: 30s
 selenoid-ui:
   container_name: selenoid-ui
   image: "aerokube/selenoid-ui"
   network_mode: bridge
   restart: always
   links:
     - ggr-ui
   ports:
     - "18080:8080"
   command: ["--selenoid-uri", "http://ggr-ui:8888"]
volumes:
 ggr:
 ggr-ui:

Selenoid-UIをGgr-UIにバインドします。
linkを張り、commandでURIをggrに繋げます。


手順3:Basic認証用Dockerfileの準備

公式のとおり、Ggrにベーシック認証を設定します。
これを実現するためにGgrのビルドにDockerfileを使用しています。
以下を同一フォルダ(c:/tmp/docker/ggr/ggr)に準備してください。

Dockerfile_ggr


FROM aerokube/ggr:latest-release
RUN set -x
RUN apk --update --no-cache --virtual build-dependencies add apache2-utils
RUN mkdir -p /etc/grid-router/quota/
COPY test.xml /etc/grid-router/quota/test.xml
RUN htpasswd -bc /etc/grid-router/users.htpasswd test test-password


ID/passwordは公式のとおりにしてありますが、こちらは必要があれば任意に変えてください。

またGgr-UIも同様に設定します。Basic認証は不要です。

Dockerfile_ggr_ui


FROM aerokube/ggr-ui:latest-release
MAINTAINER presales
RUN set -x
RUN mkdir -p /etc/grid-router/quota/
COPY test.xml /etc/grid-router/quota/test.xml

手順4:quotaファイルの準備

Selenoidのアクセス先を設定するファイルです。
ファイル名は test.xmlです。
ファイル名はBasic認証の認証IDでつくります。
こちらもDockerfileと同一フォルダ(c:/tmp/docker/ggr/ggr)に置いておきます。

test.xml


<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="77.0">
   <version number="77.0">
       <region name="1">
       <host name="172.17.0.1" port="4444" count="2" vnc="ws://172.17.0.1:4444/vnc" />
       <host name="192.168.111.111" port="4445" count="2" vnc="ws://192.168.111.111:4445/vnc" />
       </region>
   </version>
</browser>
<browser name="chrome" defaultVersion="84.0">
   <version number="83.0">
       <region name="1">
       <host name="172.17.0.1" port="4444" count="1" vnc="ws://172.17.0.1:4444/vnc" />
       <host name="192.168.111.111" port="4445" count="2" vnc="ws://192.168.111.111:4445/vnc" />
       </region>
   </version>
   <version number="84.0">
       <region name="1">
       <host name="172.17.0.1" port="4444" count="1" vnc="ws://172.17.0.1:4444/vnc" />
       <host name="192.168.111.111" port="4445" count="2" vnc="ws://192.168.111.111:4445/vnc" />
       </region>
   </version>
</browser>
</qa:browsers>


【補足】
自PCに立てているSelenoidにアクセスする場合は、DockerのデフォルトIPである172.17.0.1を使用します。


準備ができましたらそれぞれのdocker-composeを起動します。

Ggrのdocker-compose


> docker-compose up -d --build

Selenoidのdocker-compose


> docker-compose up -d


起動後はpsコマンドを叩いてhealthyになってることを確認します。


> docker-compose ps
  Name                  Command                  State                Ports
-------------------------------------------------------------------------------------
ggr           /usr/bin/ggr -listen :4444 ...   Up (healthy)   0.0.0.0:8083->4444/tcp
ggr-ui        /usr/bin/ggr-ui -quota-dir ...   Up (healthy)   0.0.0.0:8888->8888/tcp
selenoid-ui   /selenoid-ui --selenoid-ur ...   Up (healthy)   0.0.0.0:18080->8080/tcp

起動できましたね。


手順5:疎通

次はSelenoid-UIにGgr-UIがバインドされているか確認します。
ブラウザのURL欄に以下を入力してください。


http://localhost:18080/status

以下のように表示されていれば正しくバインドされています。

画像4

ポイント

・複数のSelenoidのlimit数が合計されている
・ggr-uiを閲覧できている

■Ggrの実行


やっとテストの実行です。

ここでひとつテストコードに変更を加えます。
以前設定したURLを以下に変更してください。

DemoTest.java


driver = new RemoteWebDriver(new URL(
       "http://test:test-password@172.17.0.1:8083/wd/hub"
), browser);


第2回目と同様に、テスト実行環境コンテナでdocker run します。

> cd C:\tmp\docker\mvn
> docker run -it --net="bridge" --name demo-test01 -v ${PWD}/demo-tests:/usr/src/mymaven -w /usr/src/mymaven maven mvn clean install test


Selenoid-UIを確認します。

ggr実行


無事実行されました!

Ggrの通信はどうなったでしょうか。ログを確認します。



> docker container logs -f ggr
2020/07/21 14:24:27 [-] [-] [INIT] [-] [-] [-] [-] [-] [-] [Users file is "/etc/grid-router/users.htpasswd"]
2020/07/21 14:24:27 [-] [-] [INIT] [-] [-] [-] [-] [-] [-] [Loading configuration files from "/etc/grid-router/quota"]
2020/07/21 14:26:05 [0] [0.00s] [SESSION_ATTEMPTED] [test] [192.168.16.1] [chrome-83.0] [192.168.111.111:8447:8447] [-] [1] [-]
2020/07/21 14:26:10 [0] [4.51s] [SESSION_CREATED] [test] [192.168.16.1] [chrome-83.0] [192.168.111.111:8447:8447] [873741d79a7bdcee04ab064a9e1d9088] [1] [-]
2020/07/21 14:26:15 [5] [-] [SESSION_DELETED] [-] [192.168.16.1] [-] [192.168.111.111:8447:8447] [873741d79a7bdcee04ab064a9e1d9088] [-] [-]

Selenoidのログを確認します。


2020/07/21 14:19:44 [-] [INIT] [Loading configuration files...]
2020/07/21 14:19:44 [-] [INIT] [Loaded configuration from /etc/selenoid/browsers.json]
2020/07/21 14:19:44 [-] [INIT] [Video Dir: /opt/selenoid/video]
2020/07/21 14:19:44 [-] [INIT] [Logs Dir: /opt/selenoid/logs]
2020/07/21 14:19:44 [-] [INIT] [Your Docker API version is 1.40]
2020/07/21 14:19:44 [-] [INIT] [Timezone: UTC]
2020/07/21 14:19:44 [-] [INIT] [Listening on :4444]
2020/07/21 14:26:07 [-] [NEW_REQUEST] [test] [172.17.0.1]
2020/07/21 14:26:07 [-] [NEW_REQUEST_ACCEPTED] [test] [172.17.0.1]
2020/07/21 14:26:07 [0] [LOCATING_SERVICE] [chrome] [83.0]
2020/07/21 14:26:07 [0] [USING_DOCKER] [chrome] [83.0]
2020/07/21 14:26:07 [0] [CREATING_CONTAINER] [selenoid/vnc_chrome:83.0]
2020/07/21 14:26:07 [0] [STARTING_CONTAINER] [selenoid/vnc_chrome:83.0] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6]
2020/07/21 14:26:08 [0] [CONTAINER_STARTED] [selenoid/vnc_chrome:83.0] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6] [0.93s]
2020/07/21 14:26:10 [0] [SERVICE_STARTED] [selenoid/vnc_chrome:83.0] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6] [2.12s]
2020/07/21 14:26:10 [0] [PROXY_TO] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6] [http://172.17.0.7:4444/]
2020/07/21 14:26:10 [0] [SESSION_ATTEMPTED] [http://172.17.0.7:4444/] [1]
2020/07/21 14:26:11 [0] [SESSION_CREATED] [873741d79a7bdcee04ab064a9e1d9088] [1] [4.06s]
2020/07/21 14:26:16 [5] [SESSION_DELETED] [873741d79a7bdcee04ab064a9e1d9088]
2020/07/21 14:26:17 [0] [REMOVING_CONTAINER] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6]
2020/07/21 14:26:17 [0] [CONTAINER_REMOVED] [218f757d5c1cdbd2cf81b762f179d41e8185a316d23bb032ad29645299684dd6]


自マシンではないPCにちゃんとロードバランシングされています。
(SESSION_ID:873741d79a7bdcee04ab064a9e1d9088、の部分)


■まとめ


実際の構築手順
・クライアントマシン環境のdocker-composeを作成する
・監視用docker-composeを作成する
・監視用のDockerfile、xmlを準備する
・それぞれのdocker-comoposeを実行する
・環境疎通を確認する
・テストコードのRemoteWebDriverのURLを変更する
・実行する

Ggrでの環境切り替えは、負荷分散以外にも、例えば
・AWSとAzureにそれぞれSelenoidを準備し、片方の障害時にも冗長性を担保する
・ブラウザ別に環境を切り分けて、読み込むimageを少なくすることでストレージを圧迫させない

など、ちょっとした工夫で使い道に幅が出てきます。
是非お試しください。


次回はSelenoidで実現するAndroidコンテナ環境の準備の話です。
ではでは。

――――――――――――――――――――――――――――――――――

執筆者プロフィール:石丸圭
スクラムを中心にテストのアジリティーを高めるべく
日々仕事のリードタイム・プロセスタイムの圧縮に奮闘中。
6歳4歳0歳児のパパ。
MUPうさぎクラス。

個人的なご相談はインスタDMにてどうぞー。
Instagram:@theboyalex

【ご案内】
テスト自動化のご相談は以下までお気軽にご連絡ください。
https://forms.office.com/Pages/ResponsePage.aspx?id=IkyjGtUOzUeqMMEbzjGdlSf__O4V1URMn-5BpGP8xd9UNE9ESkRPUEs1Wk9FM0REU1BXODFBSkI0MC4u

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/

みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!