Gitlab CI + DockerでRuby on Railsのテストを自動化


アドベントカレンダー20日目です。
去年はGitLab Mattermostの記事を書かせて頂きました。
今年はGitLab CIとDockerを使ったRailsの自動テスト環境について書かせていただきます。

# 環境
## GitLab側
* CentOS 7.4.1708
* GitLab Community Edition 10.2.4

## Docker側
* CentOS 7.4.1708
* Docker 1.12.6

GitLabとDockerの2台構成です。
DockerfileもDockerComposeも特に使いません。

※今回はサンプルなのでrootだったりパスワードを未設定だったりします。

# Dockerの動いてるマシンにRunnerをインストール
まず、準備としてRunnerをDockerマシンにインストールしています。
RunnerとはJenkinsでいうSlaveのようなもので、そのエージェントを仕込んでやります。
公式のドキュメントはこれを参考にしています。

[Install GitLab Runner manually on GNU/Linux](https://docs.gitlab.com/runner/install/linux-manually.html)
[Registering Runners](https://docs.gitlab.com/runner/register/index.html)

```shell
# GitLab Runner取得
wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
# 実行権限付与
chmod +x /usr/local/bin/gitlab-runner
# Runner用ユーザー追加
useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# Runnerインストール
gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
# Runnerスタート
gitlab-runner start
```
Dockerインストールの部分は端折ってます。
これでRunnerの追加は完了です。

# GitLabにRunnerを登録
先ほど作ったRunnerをGitLabに登録してやります。
サンプルとしてRoR5で`name`をMySQLに記録しておくシンプルなプロジェクト｢rails_sample｣を用意しました。

プロジェクトの左サイドバーのSettingsを押してRunners settingsのところのExpandボタンを押してメニューを開きます。
(画像はクリックした後なのでCollapseと表示されています。)


![gl1.PNG](https://qiita-image-store.s3.amazonaws.com/0/100796/9d05d009-1791-dd67-9096-0d12cc70c5f5.png)

すると、｢How to setup a specific Runner for a new project｣とRunner登録手順が書いてあります。
4ステップありますがステップ1はすでに完了しているのでステップ2からになります。
ステップ2のURLとステップ3のトークンをコピーしておいて下さい。
そうしたらDocker側で以下を実行します。

```
sudo gitlab-runner register
# 以下対話モードです。

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
<先ほどコピーしたURL>

Please enter the gitlab-ci token for this runner:
<先ほどコピーしたトークン>

Please enter the gitlab-ci description for this runner:
<このRunnerの説明>

Please enter the gitlab-ci tags for this runner (comma separated):
<このRunnerのタグ。CIで使用するための識別子みたいなモノカンマ区切り>

Whether to run untagged builds [true/false]:
<タグ指定されてないCIをこのRunnerで実行するかどうか?>

Whether to lock the Runner to current project [true/false]:
<このRunnerをこのプロジェクト専用にするかどうか?>

Please enter the executor: docker, ssh, kubernetes, virtualbox, docker+machine, docker-ssh+machine, docker-ssh, parallels, shell:
<Executerを選択。今回はDockerで実行するためdockerと入力>

Please enter the default Docker image (e.g. ruby:2.1):
<CIで使用するDockerデフォルトイメージ?今回は僕はruby:2.3.1と入力。>
```

*Runner registered successfully.
Feel free to start it, but if it's running already the config should be automatically reloaded!*
と表示されたら成功です。

念のため先ほどのトークンなどが表示されていたGitLabのページに戻って下さい。
Runnerが追加されていたら登録は完了です。


# .gitlab-ci.ymlを作成する
ここからはCI自体の設定を書いていきます。設定ファイルは`.gitlab-ci.yml`です。

まずはこんな感じです。

```yaml:.gitlab-ci.yml 

image: ruby:2.3.1

services:
  - mysql:5.6

stages:
  - test

Test:
  tags:
    - Docker
  stage: test
  script:
  - bundle install
  - rails -v

```

手始めとしてテストの前に動作確認としてRailsのバージョンを出力させてます。
`image`は使用するイメージです。ここは人によってバージョンが変わると思います。
`services`はDockerのイメージをサービスとして起動する、と考えるとわかりやすいと思います。
今回はMySQLを使用しているのでMySQLのイメージを`services`に指定します。
多分これでバージョンは出力できると思います。

ですが、このままだと`error: database is uninitialized and password option is not specified`と出ると思います。
mysqlのパスワードが設定されてないので起動できない旨のメッセージなので改良します。

```yaml:.gitlab-ci.yml 
image: ruby:2.3.1

variables:
  MYSQL_ALLOW_EMPTY_PASSWORD: 'true'

services:
  - mysql:5.6

stages:
  - test

Test:
  tags:
    - Docker
  stage: test
  script:
  - bundle install
  - rails -v
```

variablesに`MYSQL_ALLOW_EMPTY_PASSWORD`を追加しました。
今回はドサンプルなので空にしてますが適宜`MYSQL_ROOT_PASSWORD`とかでパスワード設定したりして下さい。

これでさっきのエラーは出なくなったと思います。
ここからDocker用にRailsに環境を追加します。

```yaml:config/database.yml
docker:
  adapter: mysql2
  pool: 5
  encoding: utf8
  host: mysql
  database: sample_test
  username: root
  password:
```
ここの`Host`は.gitlab-ci.yml のservicesになります。
Postgresならpostgresになると思います。
 
```yaml:secrets.yml
docker:
  secret_key_base: <bundle exec rake secretを実行して出てきたランダム文字列>
```
secrets.ymlにkey base追加しないとtestの段階でエラーになります。

これでDocker環境用の設定追加完了です。
ついにテストを実行です!
.gitlab-ci.yml にテストの処理を追加します。

```yaml:.gitlab-ci.yml 
image: ruby:2.3.1

variables:
  MYSQL_ALLOW_EMPTY_PASSWORD: 'true'

services:
  - mysql:5.6

stages:
  - test

Test:
  tags:
    - Docker
  stage: test
  script:
  - bundle install
  - rails db:create RAILS_ENV=docker
  - rails db:migrate RAILS_ENV=docker
  - rails test test/controllers/ -e docker
```
docker環境を指定してMigrationをかけてテストを実行します。
Rspecも使ってない普通のテストです。Controllerのテストだけやってみましょう。
これをPushすると...

![gl.PNG](https://qiita-image-store.s3.amazonaws.com/0/100796/ae03cb14-92f3-cfdd-3f61-ab647e0ca26e.png)

やったー!テスト成功です!
16回も回ってんのは設定忘れててミスりまくっただけです。

# おまけ

[公式ドキュメント](https://docs.gitlab.com/runner/) にはAPIのバージョンによって動かないっぽいことが書いてあるので、
[ここ](https://packages.gitlab.com/runner)からGitLab,GitLab CIのバージョンに応じたRunnerを探すといいと思います。

# おわりに

超シンプルなテスト環境の構築をご紹介しました。
Dockerを使うとなるとDockerCompose、JenkinsでやるならDocker関連のプラグインの設定等覚えることがいっぱいです。
GitLab CIはDocker使用も想定されているのでプラグイン等も必要ないのがいいなと思いました。
ここからDockerComposeを使ったりしてよりよい自動テスト環境を作る足がかりになればと思います!