既存のRuby on RailsプロジェクトにJenkins と Docker で CIを導入する

# 要約
引き継いだプロジェクトなどで既存のRailsアプリにCIがない場合に、気軽にテストを書いてCIを回す文化を醸成したいと思って対応した内容の記録です。

# 対象読者
Railsのプロジェクトを運用している方で、引き継いだプロジェクトなど何からの事情によりテストを書く環境がない、または、CI環境を構築したいが、日本語の情報が少ない（自分がそうでした）ために構築に苦労している方に向けた記事です。

# 構成
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9176/e4a84b49-cda6-ba51-bfef-44b194a8b6ba.png)
# 構築手順
## 1. ビルドマシンの準備 
   - 適当なLinuxマシンを用意してください。
   - 今回の例ではCentos7を使用しています。

## 2. dockerインストール
   - 公式の記述に従い最新版のインストールを行います。
   - https://docs.docker.com/install/linux/docker-ce/centos/
 
## 3. docker-composeインストール
   - こちらも公式より最新版のインストールを行います。
   - https://docs.docker.com/compose/install/

## 4. Jenkins(スタンドアロン版)のインストール
   - Jenkinsもdockerに閉じ込めたかったのですが、コンテナ上でdocker-compose
の使用がうまく動かなかったため、今回はやむなくJenkinsだけは
ビルドマシン上にwar配置という形をとりました。
  - https://jenkins.io/doc/book/installing/#war-file

``` sh:
# Jenkinsの起動スクリプト作成
$ mkdir ~/myjkdir
$ cd myjkdir
$ wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war .
$ cat <<EOT> start_jk.sh
JENKINS_JAVA_OPTIONS="-Xmx2048m -XX:MaxPermSize=512m -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true"
nohup java -jar jenkins.war &
EOT
$ chmod +x start_jk.sh
$ chown $USER:$USER start_jk.sh
```

## 5. Railsにビルド用の各種設定を行う
 - railsアプリをdockerにのせるための手順はこちらの通りで動作しました。
 - https://docs.docker.com/compose/rails/
 - ※ 後述していますが、この際、採用するイメージのミドルウェアのバージョンは実際に使用しているものに合わせるようにしましょう。コピペで進むとビルド出来ないなど後々不安定な挙動に悩むことになります。

## 6. ビルドマシンでdocker-composeのイメージビルド

```sh:
# 適当なディレクトリに上記リポジトリをチェックアウトして、dockerイメージのビルド
cd /myapp_dir
# Checkout from SCM .
docker-compose build
docker images
# エラーなく、イメージがビルドできていることの確認
docker-compose up
# コンテナ起動確認
docker-compose run web bundle exec rake db:create

```

## 7. Jenkinsファイルの用意

```groovy
pipeline {
  agent any
  stages {
    stage('build') {
      steps {
        sh 'docker-compose run web bundle exec rake db:create'
        sh 'docker-compose run web bundle exec rake db:schema:load'
       }
    }
    stage('test') {
      steps {
        sh 'docker-compose run web bundle exec rake test test/**/*.rb'
      }
    }
  }
}

```

- 参考：　https://medium.com/capital-one-tech/super-powering-your-enterprise-jenkins-ci-pipeline-with-docker-compose-a4f508598375
- Thank you https://medium.com/@dariendford !!

## 8. Jenkinsでビルドジョブ（pipeline）を作成し実行
 - 無事ビルド完了。
これで、テストを書いていけば自動テストが回りデグレの防止などコード品質向上に
寄与してくれることでしょう。
私も安心して眠れます。（テストを書いてから寝ろ）

# はまったポイント
以下では、上記CI環境構築の間にハマったポイントを記載します。

## 1. 既存アプリのミドルウェアバージョンを良く確認しましょう。
  - レガシーなプロジェクトだと、使用しているソフトウェアのバージョンが古いこともあり、
公式等の記述コピペで進むとうまく動かない状況に陥ります。
docker imageに採用するタグ（バージョン）を良く確認しましょう。
  - ※ 例えばruby2.3とpostgres9.4の組み合わせのシステムの場合

 - Dockerfile

```dockerfile
FROM ruby:2.3
...
```

 - docker-compose.yml

```yml
db:
 image: postgres:9.4
...
```

## 2. docker関連ファイルの改行コードはLFで統一
 - Windowsでの作業で意図せずCRLFが混入すると、dockerがエラーを出力しますのでご注意ください。

```sh

standard_init_linux.go:178: exec user process caused “no such file or directory”
```

 - 私はこれで半日溶かしました。
 - https://forums.docker.com/t/getting-panic-spanic-standard-init-linux-go-178-exec-user-process-caused-no-such-file-or-directory-red-while-running-the-docker-image/27318
 - 特にDockerfileのEntrypointに指定するコードの改行コードが問題を引き起こすことが多いようです。

# 所感

テストが気軽にかける環境をローコストで手に入れることはソフトウェア品質向上に寄与すると思っています。Rails単体でも、かなり簡単にテストができる仕組みが入っていると思いますが、さらにDB回りやシステム全体のビルドテストとなると、Dockerみたいなアプリをパッケージにできる仕組みで手軽に作って捨てる環境を作りたいところですが、現状まだまだ設定が煩雑だったり日本語情報が少なかったりと、環境構築に障壁を感じました。少しでもこの記事が同じような境遇の方のお役に立てば幸いです。