Selenium GridをGoogle Cloud Platform上で運用した知見をまとめてみた

こんにちは。生産性向上チームの宮田(@miyajan)です。モンハンもう飽きたな、と思いつつ最新作を買ってしまうのが最近の悩みです。

この記事は、Selenium/Appiumアドベントカレンダー2015の8日目の記事です。もう途切れてしまったようですが、気にせずに盛り上げていきましょう!

今回は、Selenium GridをGoogle Cloud Platform上で運用してみた知見を書きます。過去の記事でも少し書いたのですが、今回は実際に運用してみた体験に基づいています。

モチベーション

Selenium Gridは、Seleniumテスト用のブラウザ環境を複数管理するためのツールです。主に、Seleniumテストを並列実行するときに使われます。弊社のkintoneチームでは、過去の記事に書いたように、Dockerを使ってSelenium Gridを構築しています。

Dockerを使っても、数十並列でテストを動かすための大規模なSelenium Gridを構築するとなると、かなりのマシンリソース(主にCPUとメモリ)が必要になります。

また、並行開発のときなど、複数のブランチで同時にSeleniumテストを走らせられるように、一時的に必要なマシンリソースが増えることもあります。

社内で必要なマシンを調達・管理していくのはなかなか大変かつ柔軟性に欠けるので、IaaSを利用してクラウド上にブラウザ環境を用意することにしました。

運用

もろもろ調査した結果、Google Cloud Platformを使い、GCE(Google Compute Engine)のVMインスタンスでSelenium Gridを構築することにしました。全体の流れとしては、Seleniumテストを実行するCIジョブの中で以下を行います。

  • Selenium Gridを構築するインスタンスの作成
  • 構築されたSelenium Gridを使ってSeleniumテストを実行
  • インスタンスを削除

上記を実現するために、必要な作業を説明します。

スナップショットの作成

Selenium Grid用インスタンスを作成するために、元となるディスクのスナップショットを作成します。

そのために、スナップショット作成のためのインスタンスを作成し、環境構築を行います。手順は以下のような感じです。

  • インスタンスの作成
    • 作り方はクイックスタートなどをご参考に
    • このインスタンスは本運用に使うわけではないですが、動作確認を考えると、マシンタイプはn1-standard-2くらいはリソースがあった方がいいです
    • この記事では、OSはUbuntu 14.04を使用しています(単に慣れてるから)
  • sshでログイン
  • Dockerのインストール
  • Docker Composeのインストール
  • docker-compose.ymlを作成
    • 以下のような感じです
hub:
  image: selenium/hub:2.48.2
  ports:
    - "4444:4444"
node:
  image: selenium/node-chrome-debug:2.48.2
  links:
    - hub
  ports:
    - "5900"

これでSelenium Gridが構築できるようになったはずなので、動作確認してみます。docker-compose.ymlを置いたディレクトリで以下を実行してください。

$ docker-compose up -d
$ docker-compose scale node=2

上記を実行後、http://(インスタンスの外部IP):4444/grid/consoleにアクセスしてください。Selenium Gridのコンソールが表示され、ノードが2つ存在していれば設定に問題ありません。

問題なさそうであればインスタンスを停止し、スナップショットを作成します。完了したら、インスタンスは削除しても大丈夫です。

Selenium Grid用インスタンス構築をスクリプト化する

ここまでの操作はコンソールからで問題なかったのですが、CIからGCEを操作するとなるとそういうわけにはいきません。

CIからGCEを利用するために、サービスアカウントを使っています。これは、ユーザーに紐付かない、アプリケーションから利用するためのアカウントです。

サービスアカウントはコンソールから作成でき、Google APIクライアントライブラリから利用するためのjsonファイルをダウンロードできます。コマンドラインツールのgcloudからは、次のように使って認証を有効にすることができます。

$ gcloud auth activate-service-account --key-file service-account.json

コマンドラインだけでなく、pythonのクライアントライブラリでもサービスアカウントを利用できました。他の言語のライブラリでは確認していませんが、おそらく利用できるものと思われます。

認証ができれば、あとはスナップショットからインスタンスを作成するだけです。gcloud computeを使った例を書いておきます。

# スナップショットからディスク作成
$ gcloud compute --project [PROJECT NAME] disks create [DISK NAME] --size "10" --zone "asia-east1-b" --source-snapshot [SNAPSHOT NAME]
# インスタンス作成
$ gcloud compute --project [PROJECT NAME] instances create [INSTANCE NAME] --zone "asia-east1-b" --machine-type [MACHINE TYPE] --metadata-from-file "startup-script=[STARTUP SCRIPT]" --scopes "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write" --disk "name=[DISK NAME]","mode=rw","boot=yes","auto-delete=yes"

上記の[STARTUP SCRIPT]には、インスタンス起動時に実行されるスクリプトファイルを指定します。Selenium Gridを起動する場合、スクリプトの中身は下記のような感じになります。

#!/bin/bash

# 念のためにコンテナをすべて消しておく
docker rm $(docker ps -aq)

# docker-compose.ymlのあるディレクトリへ移動
cd /path/to/directory

docker-compose up -d
docker-compose scale node=[必要なノード数]

これで、インスタンスが生成されます。インスタンスの生成からSelenium Gridの起動までには、だいたい1分前後です。

そして、Seleniumテストで使用するためにSelenium GridのhubのIPを取得します。以下はgcloudとjqコマンドを使った例です。

$ gcloud compute --project [PROJECT NAME] instances list [INSTANCE NAME] --zone "asia-east1-b" --format=json | jq -r '.[].networkInterfaces[].accessConfigs[].natIP'

Seleniumテストが終わったら、インスタンスの削除を忘れずに行いましょう。

$ yes | gcloud compute --project [PROJECT NAME] instances delete [INSTANCE NAME] --zone "asia-east1-b"

このときに注意が必要なのは、削除が実行されないとインスタンスが起動し続け、余計な料金がかかってしまうということです。途中でジョブが失敗したときなどにも必ず削除が実行されるように設定しましょう。

コスト

費用

参考になるか分かりませんが、11月に実行したSeleniumテストケースの数と、実際の請求額について書いてみます。

現状、社内でGCE上のSelenium Gridを使っているのは1チームのみです。そのチームでSeleniumテストを実行するジョブは、11月は約300回実行されました。1営業日平均15回ですね。

そして、ジョブ1回ごとに実行されるSeleniumテストの数はおよそ1,000テストケースです。なので、11月に実行されたSeleniumテストケースの合計は、300×1,000=300,000なので、30万テストケースになります。

これに対して、11月のGCEの請求額は$200ほどでした。ざっくり計算すると、200÷300,000≒0.00067なので、1テストケースにつき$0.00067、日本円にして約0.083円となります。現状、インスタンスのリソースをかなり余らせているので、まだ費用削減できる余地はあります。

費用の構成要素は、次のような感じです。

  • インスタンス
    • CPUとメモリ数、起動時間で決まります
    • 費用の9割以上を占めます
  • ネットワーク
    • インターネット→GCE方向には課金されず、GCE→インターネット方向のみ課金なので、Seleniumテストに使う分には大きな金額を課金されることはありません
    • vncでつないで録画とかしてると転送量が大きくなる可能性があるので注意が必要です
  • ディスク
    • Selenium Gridの用途だとほぼ課金されません
    • SSDも選択できますが、Seleniumテストの実行時間には影響を与えないので通常のディスクで十分です

予算管理

GCE最大の残念な点として、予算の上限が設定できないことが挙げられます。

BigQueryのように気づいたら150万円溶かしていたということはないですが、間違えてインスタンスを起動しっぱなしにしてしまうと数万円くらいはかかってしまうので(体験済み)、なにかしら対策をしておくのがいいでしょう。

まず第一に考えられるのが、アラートを設定することです。これは、料金の見積もりが設定した閾値の50%、90%、100%を超えた時点で管理者にメール通知を送ります。

しかし、この料金は厳密ではなく推定に基づいているため、いまいち信憑性がありません。また、アラートが飛んできたときにはもう手遅れという心配もあります。

なので、一定時間以上起動しているインスタンスを削除するスクリプトを定期的に実行しています。これなら、消し忘れで余計な費用がかかる問題を早い段階で防げます。

とはいえ、金額の上限設定は安全のためにほしいので、もしGCE関係者がこの記事を見ることがあったら、なにとぞご検討をお願いします。

その他の知見

なぜAWSを使わないのか

EC2も検討しましたが、今回の用途だとEC2インスタンスの最小課金時間が1時間なのがネックになります。自分たちの場合、常にインスタンスが起動しているわけではなく、1回ごとのインスタンスの起動時間は20分くらいなので、かなりの時間が無駄になります。

一方で、GCEの最小課金時間は10分で、それ以降は1分単位の課金になります。これなら無駄になることはほぼありません。

さらに、最近GCEのマシンタイプにカスタムタイプが追加されました。まだベータの機能ですが、インスタンスのCPUのコア数やメモリの量をある程度自由に設定できます。

これまでの定型のマシンタイプだとリソースを余らせ気味でしたが、カスタムタイプだと必要なリソースのみ割り当てることによってコストを下げることができます。長時間使用による割引も細かく計算しているようで、定型のマシンタイプと完全に同じ構成とかにしない限りはお得になります。

このように、現状ではコスト面のメリットが大きいので、GCEを選択しています。

ネットワーク

当たり前ですが、テスト対象のサーバーが社外からアクセスできないネットワークに存在する場合、Google Compute Engine上のインスタンスからはそのままではアクセスできません。インスタンスからアクセスできるようにサーバーのIP制限を変更する、VPNを構築するといった対策が必要になります。

他にも、Seleniumテスト内でブラウザから社内ネットワークなどにアクセスするところがあると同じ問題が発生します。自分たちの場合、社内のVCS上のファイルのURLを参照していたので、修正が必要でした。

権限管理

Google Cloud Platformの残念な点として、権限管理の設定が非常に大雑把です。

まず、アカウントの権限が「オーナー」「編集可能」「閲覧可能」の3つしか選べません。実際に運用してみると、もっと細かい粒度での権限設定がほしくなります。

リスクを減らすためには、「オーナー」「編集可能」権限を持ったアカウントの数を極力少なくするしかないでしょう。

今回のようにCIなどで活用するためには、前述したようにサービスアカウントなどを活用するのがいいでしょう。このとき、API Managerで可能な限りAPIを無効にしておいたほうが無難です。

Google Cloud Platformの変化が激しい

ここ最近、Google Cloud Platformは大きく変化しています。今回この記事を書くときも、UIやリソース割り当てなど大きく変わっていて驚きました。機能が増えていくのは素晴らしいことなのですが、少し前に書かれたベストプラクティスでも現在では最適でない可能性があるということは意識しておく必要があります。

なので、可能な限り、公式のドキュメントを読んで情報を仕入れてから作業しましょう。たまにドキュメントが古くなったままのこともありますが。。

IE

現状、IEではSeleniumテストを実行していません。Windowsはコンテナが利用できないので環境のメンテが大変ですし、Seleniumの挙動も微妙に異なっていてテストコードの修正コストもかかるという問題もあります。IEのみの大きな不具合は発生しているのか、手動テストではカバーしきれないのかなど、チームにおけるIEの自動テストの重要度と照らし合わせて運用するかどうかを決めましょう。どうしても必要となった場合でも、テストケースの数をできる限り絞ることを検討しましょう。

最新のWindows ServerはDocker対応しているという話ですし、Microsoft Edgeもいろいろモダン化されているので、将来的にはIEも手軽に自動テストできる未来が待っているのではないかと思います。Microsoft様どうかよろしくお願いします。

おわりに

Selenium記事でありながら、実体はほとんどGoogle Cloud Platformのノウハウになってしまいました。しかしながら、Seleniumテストを運用するためにはブラウザ環境のインフラ構築が重要なので、IaaS関連の情報を把握しておくことも役に立つことがあると思います。

実際、これまではブラウザ環境のメンテナンスにかなりの労力を費やしていたのですが、GCE移行後はほとんど工数をかけた記憶がありません。Selenium Gridに限らず、社外に出せるものはどんどんクラウドに持っていきたいと考えています。

クラウドをうまく利用して、皆さまもぜひ幸せなSeleniumライフを送りましょう!