先日、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
は、以下のような内容が入っています。
#!/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モデルのテストを準備します。
ユーザが成人かどうかの簡単なテストです。
class User < ApplicationRecord
def adult?
age >= 20
end
end
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ファイルで管理します。
今回はアプリケーション直下へ以下のファイルを準備しました。
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
STATUS
が SUCCESS
になれば、Container Registryにイメージがあるはずです。
Pull Request時に実行する
最後に、GithubでPull Requestを作成したときに、CIを実行するようにしてみます。
といっても難しい設定は特になく、Github appで Google Cloud Build
をインストールします。
All repositories
にすると、他のリポジトリでも特別な設定が必要なく、Cloud buildが使えるようになります。
Cloud Buildへのアクセスが許可されると、GCPのコンソール上でプロジェクトの作成or選択が必要になるので、既存のプロジェクトを選択
-> cloud-build-rails(作成したプロジェクト)
を選択します。
同意して、接続すれば完了です。
動作確認
試しに、テストの内容を変えて、PRを作成してみます。
CI実行中...
ちゃんと止まってくれました。
それでは、テストを通すためにコードの修正と、ビルドしたイメージタグが現在は latest
なので、コミットのSHAにするよう修正してみます。
コミットのSHA(先頭7文字)は $SHORT_SHA
で取得が可能です。
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がつくようになりました。
まとめ
既存のプロジェクトが既にDocker化されていれば、Cloud Build上でのビルド/テストなどは、比較的短時間で行えそうだと感触でした。秘匿情報の取り扱いもKMS(Cloud Key Management Service)が使えますし、ビルドトリガーを使用して指定ブランチへのPush時にGAEへデプロイする、といったことも簡単にできそうなので、もう少しいじってみたいと思います。
気になる料金ですが、CIの実行時間1分あたり、$0.003となっているものの、1日120分までは無料です。
現在使用しているCIサービスに不満を抱えている方は、試してみてはいかがでしょうか。