Edited at

Google Cloud BuildでRSpecのテストを行う

More than 1 year has passed since last update.

先日、Google Cloud BuildとGithubの連携が発表され、CIの実現がより簡単になりました。

この記事では、簡単なRailsアプリケーションを用意して、GithubのPull Request時にRSpecでテストを実行し、パスした場合にContainer RegistryにPushするまでの流れをまとめてみました。


前提

以下のコマンドを使用します。


  • docker (18.06.0-ce)

  • gcloud (Google Cloud SDK 210.0.0)


RailsアプリのDocker化

まずはRailsアプリケーションをDocker環境で準備します。

普段はDocker Composeを使って、アプリケーションとDB、KVSなどをそれぞれのコンテナで準備するのですが、今回はCI上で実行しやすいよう、1イメージにRubyとMySQLを含めます。

なお、各バージョンについては以下の通りです。

bash-4.4# ruby -v

ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-musl]
bash-4.4# mysql -V
mysql Ver 15.1 Distrib 10.1.32-MariaDB, for Linux (x86_64) using readline 5.1
bash-4.4# rails -v
Rails 5.2.0

※ mysqlがMariaDBになっている部分については、後ほど説明します。


Dockerfile

Railsアプリを新規作成後、以下のDockerfileを作成しました。

FROM ruby:2.5.1-alpine3.7

RUN set -ex \
&& apk update \
&& apk upgrade \
&& apk add --no-cache \
build-base \
bash \
curl \
nodejs \
tzdata \
mariadb \
mariadb-client \
mariadb-dev \
openrc \
# Setup mariadb (mysql)
&& mkdir -p /run/openrc \
&& touch /run/openrc/softlevel \
&& rc-status \
&& /etc/init.d/mariadb setup \
&& gem install bundler

WORKDIR /web

COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install

ADD . .
RUN chmod +x /web/rspec.sh

Rubyの公式イメージを土台にしています。

軽量化を図ってalpineにしたものの、前述したDBが同一イメージに入っているため、 943MB となりました。

この辺りはもう少し見直したいと思います…

接続先のDBですが、現在、alpineのパッケージマネージャでMySQLをインストールするとMariaDBが入ります。

MariaDBとは、MySQLから派生したオープンソースのRDBだそうで、パフォーマンスも良いらしいです。

細かい違いはあるものの、今回の動作確認では問題ないのでこのまま進めます。

rspec.sh は、以下のような内容が入っています。


rspec.sh

#!/bin/bash

# MariaDBの起動
rc-service mariadb start

rails db:create db:migrate
bundle exec rspec


MariaDBの起動後、Railsのいつものやつと、RSpecの実行コマンドです。

最終的には、CI上でこのシェルスクリプトが実行されます。


動作確認

ここまで一旦、動作確認が出来るか試してみましょう。

なにはともあれビルドします。今回はcloud-build-railsというイメージ名にしました。

$ docker build -t cloud-build-rails:v1 .

コンテナ内に入ります。

$ docker run -it -p 3000:3000 cloud-build-rails:v1 bash

MariaDBの起動、DBの準備、サーバーの起動をします。

# コンテナ内

$ rc-service mariadb start
$ rails db:create db:migrate
$ rails s

ブラウザから http://localhost:3000/ にアクセスして、Railsのオリジナルページが表示されればOKです。


モデルのテスト

本題ではないので、さくっと最小限のUserモデルを作っておきます。

$ rails g model user name:string age:integer

$ rails db:migrate

RSpecを導入して、Userモデルのテストを準備します。

ユーザが成人かどうかの簡単なテストです。


app/models/user.rb

class User < ApplicationRecord

def adult?
age >= 20
end
end


spec/models/user_spec.rb

require "rails_helper"

RSpec.describe User, type: :model do
it "成人かどうかが分かること" do
user = User.new(name: "enta", age: 25)
expect(user.adult?).to eq true
end
end


問題なく通りますね。


Cloud Build

本題です。


プロジェクトの作成

まずは、GCPのコンソールからプロジェクトを作成し、Cloud Build APIを有効にします。

サンプルとしてcloud-build-railsというプロジェクト名にしました。


コマンドライン上でプロジェクトの設定

Cloudリソースへのアクセスを承認後、コマンドライン上でプロジェクトの設定を行います。

PROJECT_ID には、作成したプロジェクトのIDを指定します。

$ gcloud auth login

$ gcloud config set project PROJECT_ID


ビルドリクエストの作成

ビルドイメージの作成やテストの実行、デプロイの設定などをYAMLファイルで管理します。

今回はアプリケーション直下へ以下のファイルを準備しました。


cloudbuild.yaml

steps:

- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/cloud-build-rails', '.']
- name: 'gcr.io/$PROJECT_ID/cloud-build-rails'
args: ['/bin/bash', '/web/rspec.sh']

images: ['gcr.io/$PROJECT_ID/cloud-build-rails']


Cloud Buildは、stepsに書かれている内容を上から順に実行していきます。

ここでは、大きく2つのステップがあります。

1つはイメージのビルドです。

gcr.io/cloud-builders/docker は、すでにGoogleが用意している環境を使用する宣言です。

他にも git や 言語の go まで用意されており、詳しくはこちらで確認できます。

2つ目に実行しているのは、RSpecのテストです。

序盤で準備したシェルスクリプトを、先程ビルドした環境内で行います。

テストが終わると、最後に imagesにある、ビルドしたイメージがContainer RegistryにPushされます。

次のコマンドで動作確認をしてみます。

$ gcloud builds submit . --config=cloudbuild.yaml

STATUSSUCCESS になれば、Container Registryにイメージがあるはずです。

Container_Registry_-_cloud-build-rails.png


Pull Request時に実行する

最後に、GithubでPull Requestを作成したときに、CIを実行するようにしてみます。

といっても難しい設定は特になく、Github appで Google Cloud Buildをインストールします。

スクリーンショット 2018-08-05 22.51.24.png

All repositories にすると、他のリポジトリでも特別な設定が必要なく、Cloud buildが使えるようになります。

スクリーンショット 2018-08-05 22.51.51.png

Cloud Buildへのアクセスが許可されると、GCPのコンソール上でプロジェクトの作成or選択が必要になるので、既存のプロジェクトを選択 -> cloud-build-rails(作成したプロジェクト)を選択します。

スクリーンショット 2018-08-05 22.53.26.png

スクリーンショット 2018-08-05 22.53.48.png

同意して、接続すれば完了です。


動作確認

試しに、テストの内容を変えて、PRを作成してみます。

スクリーンショット 2018-08-06 2.37.53.png

CI実行中...

スクリーンショット 2018-08-06 2.39.11.png

ちゃんと止まってくれました。

それでは、テストを通すためにコードの修正と、ビルドしたイメージタグが現在は latest なので、コミットのSHAにするよう修正してみます。

コミットのSHA(先頭7文字)は $SHORT_SHA で取得が可能です。


cloudbuild.yaml

steps:

- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/cloud-build-rails:$SHORT_SHA', '.']
- name: 'gcr.io/$PROJECT_ID/cloud-build-rails:$SHORT_SHA'
args: ['/bin/bash', '/web/rspec.sh']

images: ['gcr.io/$PROJECT_ID/cloud-build-rails:$SHORT_SHA']


追加コミットをすると、テストが通り、Pushされたイメージのタグには、最新のSHAがつくようになりました。

スクリーンショット 2018-08-06 2.55.53.png

Container_Registry_-_cloud-build-rails 3.png


まとめ

既存のプロジェクトが既にDocker化されていれば、Cloud Build上でのビルド/テストなどは、比較的短時間で行えそうだと感触でした。秘匿情報の取り扱いもKMS(Cloud Key Management Service)が使えますし、ビルドトリガーを使用して指定ブランチへのPush時にGAEへデプロイする、といったことも簡単にできそうなので、もう少しいじってみたいと思います。

気になる料金ですが、CIの実行時間1分あたり、$0.003となっているものの、1日120分までは無料です。

現在使用しているCIサービスに不満を抱えている方は、試してみてはいかがでしょうか。