【Selenoid -2】Selenoidをルーティング Ggrを構築する(前編)

■Ggrって何?

今日はGgr(Go grid router)をご紹介します。
こちらも前回と同様、aerokubeが提供しているSelenoidプロダクトのひとつで、構築したSelenoidをルーティングしてくれます。

aerokube.com

今回のエントリはその前半です。(意外と長くなってしまった)

■何がうれしいの?

docker-engine上に構築したSelenoidは、ブラウザimageさえあれば幾らでもコンテナ化して並列実行することができますが、最終的にはdockerが乗っているハードウェアのリソース制限を受けます。
もしブラウザコンテナを複数起動してテストの並列実行をするのであれば、サーバスペックを上げるか、サーバの複製をして実行を分配してやるしかありません。
そして恐らく一般的には後者をチョイスすることになると思います。

f:id:theboyalex:20200523004241p:plain
selenoid簡易構成図

さて、ここで問題になるのがいかに並列実行環境にアクセスするか、です。

例えばSelenoidをremote実行する場合

WebDriver driver = new RemoteWebDriver(
    new URL("http://selenoid.example.test01.com:4444")
    ,capabilities
);
return driver;

といった記述をCIのJOBから施すことになると思いますが、複数サーバに対して並列実行を実現しようとするとホスト情報を動的に切り替える必要があります。
この場合CI内でpipeline分岐をするか、さもなくばシェルでゴリゴリ切り替えることになると思います。

例:Jenkinsfileのpipelineでchromefirefoxの実行するselenoidホストを分けて記述

pipeline{
    stages{
        stage('Test'){
            steps{
                parallel(
                    "chrome":{
                        sh "gradle -Dcapabilities.remote=http://selenoid.example.test01.com:4444 -Dcapabilities.browser=chrome -Dcapabilities.version=83.0 clean test "
                    },
                    "firefox":{
                        sh "gradle -Dcapabilities.remote=http://selenoid.example.test02.com:4444 -Dcapabilities.browser=firefox -Dcapabilities.version=76.0 clean test "                    
                    }
                )
            }
        }
    }
}

これではホストの増減だけではなく、ブラウザの種類や対象バージョンに対し毎回JOBやシェルの書き換えを施さないとならず正直手間です。

ここでGgrさんが颯爽と登場します。

■Ggrの使い方

Ggrでは、この複数建っているSelenoid環境をルーティングして実行してくれます。
アクセス先はGgr用に開放しているホストの指定ポートに対していつも通りremote実行すればOKです。

Ggr用にdocker-compose.ymlを準備していますので、まずはdocker-composeを見てみましょう。

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
volumes:
  ggr:

まず公式のお作法に則って作成します。 必要なファイルは2つ。

1. ユーザファイル(ユーザ資格情報)
2. quotaファイル(Selenoidのルーティング情報)

今回はここはDockerfileで準備をします。

FROM aerokube/ggr:latest-release
MAINTAINER tba
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

①ユーザ資格情報

まずユーザ資格情報はDockerfile内で発行してます。

ボクの場合はDockerfileを使用して準備しましたが、Dockerfileに書きたくないよって方もいると思います。
(認証情報がファイルに残るし、RUNするとコンテナの履歴にも残るため)
その場合はhtpasswdは個別に実行してください。

また公式とは異なるbasic認証をかけたいよって方はこの部分を適宜変更してください。

②quotaファイル

次に事前にdockerホスト側で準備していたquotaファイルをdockerイメージにコピーします。

<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="74.0">
    <version number="74.0">
        <region name="1">
        <host name="selenoid.example.test01.com" port="4444" count="2" vnc="ws://selenoid.example.test01.com:4444/vnc" />
        <host name="selenoid.example.test02.com" port="4444" count="2" vnc="ws://selenoid.example.test02.com:4444/vnc" />
        </region>
    </version>
</browser>
<browser name="chrome" defaultVersion="81.0">
    <version number="80.0">
        <region name="1">
        <host name="selenoid.example.test01.com" port="4444" count="1" vnc="ws://selenoid.example.test01.com:4444/vnc" />
        <host name="selenoid.example.test02.com" port="4444" count="1" vnc="ws://selenoid.example.test02.com:4444/vnc" />
        </region>
    </version>
    <version number="81.0">
        <region name="1">
        <host name="selenoid.example.test01.com" port="4444" count="1" vnc="ws://selenoid.example.test01.com:4444/vnc" />
        <host name="selenoid.example.test02.com" port="4444" count="1" vnc="ws://selenoid.example.test02.com:4444/vnc" />
        </region>
    </version>
</browser>
</qa:browsers>

quotaファイルがルーティングのメイン設定になります。
どのブラウザをどのホストで実行することができるのかはこちらでコントロールすることになります。

■実行

ではdocker-composeを実行しましょう。

$ docker-compose up -d --build
Creating network "ggr_default" with the default driver
Creating volume "ggr_ggr" with default driver
Building ggr
Step 1/7 : FROM aerokube/ggr:latest-release
 ---> aca0cf2239c9
Step 2/7 : MAINTAINER tba
 ---> Using cache
 ---> 8c222b60c084
Step 3/7 : RUN set -x
 ---> Using cache
 ---> 68674af6b560
Step 4/7 : RUN apk --update --no-cache --virtual build-dependencies add apache2-utils
 ---> Using cache
 ---> f17107ec608e
Step 5/7 : RUN mkdir -p /etc/grid-router/quota/
 ---> Using cache
 ---> 067a7550a26a
Step 6/7 : COPY test.xml /etc/grid-router/quota/test.xml
 ---> Using cache
 ---> 9f0f03f146b7
Step 7/7 : RUN htpasswd -bc /etc/grid-router/users.htpasswd test test-password
 ---> Using cache
 ---> 3034fb0a8de1

Successfully built 3034fb0a8de1
Successfully tagged aerokube/ggr:latest
Creating ggr ... done

psを叩いてhealthチェックします。

$ docker-compose ps
Name              Command                  State               Ports
-----------------------------------------------------------------------------
ggr    /usr/bin/ggr -listen :4444 ...   Up (healthy)   0.0.0.0:4444->4444/tcp

logsコマンドでログを確認。

$ docker-compose logs -f
Attaching to ggr
ggr    | 2020/05/22 17:30:49 [-] [-] [INIT] [-] [-] [-] [-] [-] [-] [Users file is "/etc/grid-router/users.htpasswd"]
ggr    | 2020/05/22 17:30:49 [-] [-] [INIT] [-] [-] [-] [-] [-] [-] [Loading configuration files from "/etc/grid-router/quota"]

quotaファイルの読み込みチェック。

curl -s http://test:test-password@ggr.example.test.com:4444/quota
[{"Name":"firefox","DefaultVersion":"74.0","DefaultPlatform":"","Versions":[{"Number":"74.0","Platform":"","Regions":[{"Name":"1","Hosts":[{"Name":"selenoid.example.test01.com","Port":4444,"Count":2,"Username":"","Password":"","VNC":"ws://selenoid.example.test01.com:4444/vnc","Scheme":""}]}]}]},{"Name":"chrome","DefaultVersion":"81.0","DefaultPlatform":"","Versions":[{"Number":"80.0","Platform":"","Regions":[{"Name":"1","Hosts":[{"Name":"selenoid.example.test01.com","Port":4444,"Count":1,"Username":"","Password":"","VNC":"ws://selenoid.example.test01.com:4444/vnc","Scheme":""}]}]},{"Number":"81.0","Platform":"","Regions":[{"Name":"1","Hosts":[{"Name":"selenoid.example.test01.com","Port":4444,"Count":1,"Username":"","Password":"","VNC":"ws://selenoid.example.test01.com:4444/vnc","Scheme":""}]}]}]}]```

ログにもListenされたあとが出てきます。

ggr    | 2020/05/22 17:33:23 [0] [-] [QUOTA_INFO_REQUESTED] [test] [***.***.***.***] [-] [-] [-] [-] [-]
ggr    | 2020/05/22 17:34:07 [1] [-] [QUOTA_INFO_REQUESTED] [test] [***.***.***.***] [-] [-] [-] [-] [-]

さて、あとは今までremotedriverで設定していた箇所を
http://test:test-password@ggr.example.test.com:4444
これに書き換えてテスト起動すれば、Ggrがルーティングしてその先のSelenoidをキックしてくれます。

ちょっと長くなってしまったので、次回に続きます。

ではでは。