こんにちは、サーバーサイドエンジニアのT.Tanakaです。
私の所属するプラットフォーム運用部ではCLOMOのサービス監視を実施しており、サーバーリソースの監視やヘルスチェック用エンドポイントへのサービス死活監視、ログのエラー監視等を実施しています。 これらの監視で多くの問題が検知できるのですが、以下のようなケースでは実際のブラウザ操作による監視を実施したいという状況も存在していました。
- ログイン等のブラウザ操作を伴うサービス正常性チェック
- ブラウザでJavaScriptまで動作した上でのページ内容のチェック(改ざん検知など)
このような状況において、Ruby+Dockerを利用して想像より手軽にブラウザオートメーションによる監視の仕組みが実現できたため、紹介をさせていただきます。
想定する要件
E2Eテスト用のWEBサービスは多く存在しますが、そのようなサービスを新規導入するほど監視したいケースが多いわけではないため、導入・環境構築もメンテナンスもさほど手間を掛けずにブラウザオートメーション監視ができないか検討を開始しました。
想定していた簡単な要件は以下です。
- パスワード認証画面のログイン程度の操作を実施したい
- ブラウザに特にこだわりはなく、Chromeなどのメジャーなブラウザで確認できれば良い
- コードを記述する言語はRubyがよい(弊社サーバーサイドはRubyエンジニアが多いため)
- 可能であればDocker上で実行したい(導入・メンテナンスを簡単にするため、専用のサーバー環境の構築・管理を避けたい)
候補となった3種類のブラウザオートメーションOSSの比較
候補として現在主流の3つのブラウザオートメーション技術である「Selenium」「Puppeteer」「Playwright」を簡単に比較をしてみました。
Selenium
- Seleniumは、ThoughtWorks社によって開発されたWebアプリケーションのUIテストを自動化のためのE2Eテストフレームワーク
- C#、Groovy、Java、Perl、PHP、Python、Ruby、Scala 等の一般的なプログラミング言語でテストを作成可能
- テストはほとんどの最新のWebブラウザ(Chrome/Chromium、Firefox、Internet Explorer、Edge、Opera、Safari等)に対して実行できる
- Dockerへの対応
- docker-seleniumを利用し対応可能である想定
- 複数ブラウザで並行テストが可能な「Selenium Grid」が動作可能なイメージと単一ブラウザ環境の「Standalone」のイメージが公開されている
- 「Selenium Grid」は今回の要件と比べた場合設定や機能が過多な印象
- 「Standalone」は候補にあがるがイメージ容量が1.2GB程度と他より重め
Puppeteer
- Googleによって開発された、ChromeをDevToolsプロトコルで制御するためのAPIを提供するNode.jsライブラリ
- PuppeteerはSeleniumのようなテストフレームワークではなくシンプルな自動化ツール
- 対応ブラウザはChrome、Firefox
- Rubyへの対応状況
- PuppeteerはNode.jsライブラリであるためRubyでの利用はできない。しかし、Puppeteerの機能をRubyで実行できるようRubyで実装されたpuppeteer-rubyを利用することで対応可能
- Dockerへの対応
- puppeteer-ruby作者により利用可能なサンプルが公開されている
- Alpine Linuxをベースにpuppeteer-rubyを動かすRubyとChromiumが1つのコンテナに入った非常にシンプルな構成であり、容量も0.57GB程度と他より軽量
- puppeteer-rubyの他にもDevToolsプロトコルを使用してブラウザオートメーションができるRubyライブラリにはFerrumやCupriteがあるが、以下のポイントについてpuppeteer-rubyにアドバンテージが有り、今回の要件には使いやすいと判断
- 指定したSelectorが画面遷移後に描画されるまで待つwaitForSelectorという命令を持つ
- 開発者自身で作成されたすぐにDockerで動かすことができるサンプルがある
Playwright
- Microsoftにより開発されているWebテスト・自動化のためのフレームワーク
- Puppeteerの元開発メンバーが中心となって開発されておりChromium、Firefox、WebKit等主要ブラウザについてクロスブラウザのWeb自動化を可能にするNode.jsライブラリ
- Rubyへの対応状況
- PlaywrightはRubyへの対応はされていないが、PlaywrightをRubyで操作できるライブラリplaywright-ruby-clientが存在する
- Dockerへの対応状況
- Playwrightの公式Docker Imageによって実施可能である想定。
- 公式イメージが1.75GB程度と比較的重く、複数コンテナ構成となるため若干ではあるが、puppeteer-rubyより複雑な構成となる 今回の要件に合致するものとして、Docker上で最もシンプルな構成でヘッドレスブラウザを動かしブラウザオートメーションを実現できると想定されたPuppeteer(puppeteer-ruby)を第一候補として選定しました。
puppeteer-rubyとは
- シンプルで信頼性が高いNode.jsのブラウザオートメーションライブラリ「Puppeteer」をRubyで実装しなおし、Puppeteerの機能をRubyで利用できるようにしたライブラリ
- サンプルが充実しており、Dockerの環境があればすぐに実行可能
- 弊社エンジニアYusukeIwakiさんが開発
- 🎊🎊🎊2021年「第13回フクオカRuby大賞 優秀賞・マネーフォワード賞」🎊🎊🎊
- 実はこれが一番の選定理由だったりします(苦笑)
監視スクリプトの開発
基本はpuppeteer-rubyのサンプルの内容をもとにpuppeteerのドキュメントも参考にしながら実装していきました。 まずはサンプルの実行から。(macOS 11.3.1、Docker Desktop 4.6.1環境で確認)
# 任意のフォルダに移動 cd <任意のフォルダ> # Puppeteer-ruby のサンプルを git clone git clone git@github.com:YusukeIwaki/puppeteer-ruby-example.git # フォルダ移動 cd puppeteer-ruby-example/docker_chromium # ビルドする docker-compose build # サンプルの実行 docker-compose run ruby ruby 1.capture_a_site_chromium.rb
エラーを検知した場合にスクリーンショットを取得し、アラートメールを送信できるようにします。 (※ 以下のコードは実装の概要を示すもので、動作を保証するものではございません。)
require 'puppeteer' require_relative './sample_mailer.rb' launch_options = { executable_path: ENV['PUPPETEER_EXECUTABLE_PATH'], args: ['--no-sandbox'], } Puppeteer.launch(**launch_options) do |browser| page = browser.new_page page.goto("https://www.i3-systems.com/") #~~~(ブラウザで操作したい内容を記述)~~~ rescue => e # エラーが起きたらメールを送信! page.screenshot(path: 'error.png') SampleMailer.sample_mail(e: e).deliver! end
メール送信用の処理はmail GEMのみを使用したシンプルな構成にしています。
require 'mail' class SampleMailer def sample_mail(e:) Mail.new do from $FROM_ADDRESS to $TO_ADDRESS subject "エラーを検知しました。" body "#{e.class}" + "\n" + " #{e}" + "\n" + "#{e.backtrace.join("\n")}" add_file "./error.png" if File.exist?("./error.png") end end end
運用環境
Dockerがインストールされた環境であれば、docker-composeをcrontab等で実行することが手軽にできると思います。 弊社ではAzure Kubernetes Serviceを使用しており、他の監視バッチがAKS上のCronjobで動作しており、運用環境上のメールサーバーを共用できるため、以下のような構成でAKS上のCronjobとして動作させています。
運用結果
ログイン操作を伴う監視ケースの直近1ヶ月のエラーログを確認したところ、puppeteer-ruby起因のエラーはなく高信頼の監視が実現できている状況です。本ケースにおいてお客様や他部門のメンバーからの指摘で異常を知るケースが減り、より信頼できる運用監視ができるようになり満足できる結果となりました。 今回は想像していたよりも少ないコストで手軽にブラウザオートメーション監視が実現でき、また、今後も監視を充実していける環境を手に入れることが出来ました。Ruby&Dockerを利用できるエンジニアがいる環境で手軽にブラウザ監視を実施したい場合「puppeteer-ruby」は一つの選択肢になるのではと思います。
最後に、私たちは一緒に働く仲間を募集しています!