💎

GitHub ActionsでRuby on Railsのテストを実行する(CIの構築) 2020-12版

2020/12/17に公開

はじめに

今まではCircleCIかWerckerを使っていたけど、GitHub Actionsが安定してきているようなので使い始めてみることにした。
CircleCIのWeb UIもそれほど使いやすいとは思ってなかったのも理由の1つ。

コスト比較

かなり安いとの記事を発見。
https://qiita.com/bigwheel/items/2ab7deb237122db2fb8d#蛇足-github-actions安すぎない

無料プランで比較すると、
月あたりCircleCIが約1000分、GHAは 2000分 のマシン時間が使える。(どちらも 2 cpu)
https://docs.github.com/ja/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners
https://circleci.com/ja/pricing/

テンプレートを使ってみる

こちらの記事を参考に、GitHubのテンプレートでやってみる
https://zenn.dev/dodonki1223/articles/b26d3689bbb012d9e88c

GitHubのWebから全てできるので10分程度で完了。

設定内容としては、

  1. GitHubのコードをチェックアウト
  2. Ruby をセットアップ
  3. Rspecを実行

実行すると、DBへの接続エラーとなる。このGitHubのテンプレートはRubyを実行する設定だけなのでRailsに必要なDBなどの設定などがないため。

RailsのRspecを実行するための設定を作る

GitHub Actions公式のドキュメント を見ると、CircleCIが分かっていれば比較的分かりやすい

このあたりの2次情報を見て、イメージを補足
https://qiita.com/tk_hamaguchi/items/50c819094125b5615912
https://qiita.com/DaichiSaito/items/f0a79f3eac04f1034a30

以下の方向性で設定ファイルを作成

  • DB, Cacheサーバーはservices(Dockerコンテナ)で構築
  • メインの実行環境もDockerコンテナで Rubyイメージを使う
    • GitHub ActionsのRuby Setupは長期的なサポートとActionsのセキュリティに懸念があるので使わない
  • npm, gem をキャッシュする

作成した設定ファイル

.github/workflows/test.yml
name: Test
on: [push]
jobs:
  run:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:10
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
        env:
          POSTGRES_HOST_AUTH_METHOD: 'trust'
      redis:
        image: redis:alpine
        options: --health-cmd "redis-cli -h localhost ping" --health-interval 10s --health-timeout 5s --health-retries 15
    container:
      image: ruby:2.6.2
      env:
        RAILS_ENV: test
        DATABASE_HOST: postgres
        REDIS_URL: redis://redis:6379/1

    steps:
      - uses: actions/checkout@v2
      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          # npm キャッシュファイルは Linux/macOS の「~/.npm」に保存される
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-
      - name: Cache bundle gems
        uses: actions/cache@v2
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gem-${{ env.cache-name }}-
            ${{ runner.os }}-gem-
            ${{ runner.os }}-
      - name: Install Node.js and Yarn
        run: |
          # https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions
          curl -sL https://deb.nodesource.com/setup_12.x | bash -
          apt-get install -y nodejs
          # https://classic.yarnpkg.com/en/docs/install#debian-stable
          curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
          echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
          apt update && apt install yarn
      - name: Install Bundler
        run: gem install bundler --no-document -v $(grep "BUNDLED WITH" -1 Gemfile.lock | tail -n 1)
      - name: Bundle install
        run: bundle install --path=vendor/bundle --jobs 4 --retry 3
      - name: Yarn install
        run: bundle exec rails yarn:install
      - name: DB setup
        run: bundle exec rails db:setup
      - name: Run rspec
        run: bundle exec rspec

設定ファイル解説

name: Test

ワークフローの名前。好みで変えてOK

  run:

ジョブの名前。好みで変えてOK
この設定だと、Test.run のように表示されます。 build と記述する例が多かったのですが、 Test.build となるので、個人的には冗長に感じました。

    runs-on: ubuntu-latest

ジョブを実行するホストマシンの指定。 ubuntu-latest は今はUbuntu 18.04
https://docs.github.com/ja/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on

    services:

別コンテナで起動するミドルウェアなどを定義します。Docker-compose の service と同じ感じ。

      postgres:
        image: postgres:10
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
        env:
          POSTGRES_HOST_AUTH_METHOD: 'trust'

PostgreSQLを Dockerイメージで起動します。
optionsの起動チェックはこのあたりを参考にしています。
https://docs.github.com/ja/free-pro-team@latest/actions/guides/creating-postgresql-service-containers#コンテナ内でのジョブの実行

      redis:
        image: redis:alpine
        options: --health-cmd "redis-cli -h localhost ping" --health-interval 10s --health-timeout 5s --health-retries 15

RedisをDockerイメージで起動します。
こちらも optionsの起動チェックは公式を参考にしています。
https://docs.github.com/ja/free-pro-team@latest/actions/guides/creating-redis-service-containers#コンテナ内でのジョブの実行

    container:
      image: ruby:2.6.2
      env:
        RAILS_ENV: test
        DATABASE_HOST: postgres
        REDIS_URL: redis://redis:6379/1

Ruby 2.6.2のDockerイメージでジョブを実行します。
DATABASE_HOST はRailsの設定(database.ymlなど)で指定できるようにしあります。Docker-composeと同じくコンテナ同士のネットワークが構築されるので、Postgreのサービス名を指定しています。
REDIS_URL も同じく redisの接続先を設定しています。

      - uses: actions/checkout@v2

GitHubのコードをコンテナにチェックアウトします。
https://github.com/marketplace/actions/checkout

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          # npm キャッシュファイルは Linux/macOS の「~/.npm」に保存される
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

node moduleのキャッシュです。以下を参考にしてます。
https://docs.github.com/ja/free-pro-team@latest/actions/guides/caching-dependencies-to-speed-up-workflows#cacheアクションの利用
https://qiita.com/DaichiSaito/items/f0a79f3eac04f1034a30

CirclCIと比較すると cache actionsを使うことで、キャッシュの保存を記述しなくてもジョブ完了後に自動的に保存されるようです。
https://github.com/marketplace/actions/cache

      - name: Cache bundle gems
        uses: actions/cache@v2
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gem-${{ env.cache-name }}-
            ${{ runner.os }}-gem-
            ${{ runner.os }}-

node modulesと同じですが、パスなどを変えてます。

      - name: Install Node.js and Yarn
        run: |
          # https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions
          curl -sL https://deb.nodesource.com/setup_12.x | bash -
          apt-get install -y nodejs
          # https://classic.yarnpkg.com/en/docs/install#debian-stable
          curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
          echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
          apt update && apt install yarn

結構ハマるポイントなので、公式のドキュメントを見てバージョン決めてインストールしました。

      - name: Install Bundler
        run: gem install bundler --no-document -v $(grep "BUNDLED WITH" -1 Gemfile.lock | tail -n 1)
      - name: Bundle install
        run: bundle install --path=vendor/bundle --jobs 4 --retry 3
      - name: Yarn install
        run: bundle exec rails yarn:install
      - name: DB setup
        run: bundle exec rails db:setup
      - name: Run rspec
        run: bundle exec rspec

このあたりは、通常のRailsでの実行と同じなので説明は割愛

感想

  • GitHubがテンプレートを用意してくれているものは最初の一歩としては優秀。Rubyの実行だけなら5分かからずできる
  • Circle CIなどの外部サービスと比べて、GitHubの画面の中に Actions として表示されるので見やすい。追加でログインするのとか地味にストレス。ワークフローの開始も遅延が少ない気がする(数秒の違いですが)
  • 小さいRspecが5つくらいのRailsプロジェクトを実行したところ、実行に5分程度かかった。2回目以降にキャッシュが効くと2分弱で完了。他のサービスと比べても多分有意差はなさそう。

まとめ

Discussion