モノリシックなRuby on Railsアプリケーションの膨大なRSpecをGitLab CI/CDを使って並列実行する

はじめに

こんにちは。Optimal Bizのサーバーサイドに関する開発を担当している伊藤です。

突然ですが皆さんは開発中、単体テストをどのように実施していますでしょうか。
Optimal BizではGitLabのマージリクエスト毎に単体テストを実施し、 その結果がマージリクエストに出るようにしています。

こんな感じです(モザイク部分には失敗したテストの詳細が表示されてます)

f:id:optim-tech:20200310185409p:plain

しかし、歴史が長く単体テストが膨大になったプロジェクトの場合は実施に時間がかかり、マージリクエスト毎のタイムリーな実行が難しくなってきます。
Optimal Bizでは70,000ケース以上の単体テストがあり、シングルスレッドで実行すると24時間以上かかってしまう状況でした。

そこで今回は単体テストを実行するPCを20台に分散させ、50並列で実施することによって、実施時間を約1時間程度に短縮したアプローチをご紹介します。

GitLab CI/CDのparallelオプション

GitLab CI/CDにはparallelというオプションが存在します。 この設定を行うと、同じスクリプトを並列に実行させることが可能です。

この設定を行ったjobは以下の環境変数が設定された状態で並列実行されます。

環境変数 設定される値
CI_NODE_TOTAL 並列実行数(parallelに指定した値と同じ数字)
CI_NODE_INDEX 並列実行されるjob毎の採番(1〜parallelに指定した値)

単体テストの実施ファイルを分割する

上記の環境変数を利用して、実施する単体テストのファイルを分割するスクリプトを作成します。 こんな感じです。

# rspec_files.rb

specs = Dir['./spec/**/*_spec.rb']
puts specs.each_slice(specs.size / ENV['CI_NODE_TOTAL'].to_i).to_a[ENV['CI_NODE_INDEX'].to_i]

なお、GitLab CIの公式ドキュメントでは2020/03/11現在、「semaphore_test_boosters」というGemを利用した例が記載されていますが、 このGemはテストを行った結果をGemの作成者に送付しているように見受けられたので利用を避けています。

.gitlab-ci.ymlを設定する

最後に、GitLab CI/CDの公式ドキュメントに沿って設定をしてきます。 RSpecを用いたサンプルもあるのでわかりやすいですね! parallelを利用した並列実行である場合も、GitLab CIが自動的にテスト結果を収集マージしてくれます。

.gitlab-ci.ymlの例はこんな感じになります。

rspec:
  stage: test
  parallel: 20
  script:
    - bundle install
    - bundle exec ruby rspec_files.rb | xargs bundle exec rspec --format RspecJunitFormatter --out rspec.xml
  artifacts:
    reports:
      junit: rspec.xml

これによって以下のようにジョブが分散されるため、GitLab Runnerが複数いればテストを複数のPCで分散して実行することできます!

f:id:optim-tech:20200310184906p:plain

GitLab Runnerを用意する

GitLab Runnerの公式のドキュメントにある手順の通りに実施します。

2020/03/11現在、UbuntuにGitLab Runnerをインストールする手順は以下のような感じでした。

  1. GitLabの公式リポジトリを追加する

    $ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash

  2. apt-getコマンドを利用してGitLab Runnerをインストール

    $ sudo apt-get install gitlab-runner

  3. 公式のGitLabRunner登録手順にしたがって、GitLabに登録する

    $ sudo gitlab-runner register

    対話形式で必要な項目を入力していきます。
    必要な項目はGitLabのプロジェクトページから「Settings > CI/CD > Runners」のページに遷移すると確認することができます。
    このときにexecutorの種類も聞かれるのですが、よくわからない場合はshellを選択するのがおすすめです。

最後に

今回はGitLab CI/CDを使って膨大なRSpecを並列実行する方法を紹介しました! ただし、このままだとたくさんのPCを手動で管理しなければなりません。
その解決のために次回はGKEをGitLab Runnerとして利用する方法をご紹介したいと思っています!

オプティムでは開発環境を日々改善していき、より良いアプリケーションを一緒に作るエンジニアを募集しています!

www.optim.co.jp