Docker with ECS × Railsを実現させるために考えたこと(CI編)

こんにちは。エンジニアの志村です。
前回・前々回とRailsをDocker運用する記事を書いておりますが、今回はCI編です。
過去の記事は下記になります。

cluex-developers.hateblo.jp

導入編でも書いた通り、CIはJenkinsを使用することにしました。 Dockerでの運用前はCircleCIを使用しておりました。

現在の構成

構成

MasterとSlaveの2段構成にしています。
Masterにジョブを置くとジョブの管理が面倒になるのと、ジョブの組み合わせ次第では不具合が起きる可能性があるので、Masterにはジョブを持たせず、テストやlint等はslaveで行うように設定しています。
Master, Slave共にDocker + ECSで構築しています。
ECSでSlave用のクラスタを用意し、

Amazon EC2 Container Service Plugin - Jenkins - Jenkins Wiki

を使用してSlaveを管理しています。

  • Pipelineを使用。Pipelineは全てJenkinsfileにて記述し、Gitリポジトリで管理
  • Docker+ECSでMaster & Slaveを管理
  • docker-composeでテスト・lintを走らせる

上記のように、Jenkinsコンテナ内でさらにRailsのDockerコンテナを起動している状態となります。所謂Docker in Dockerです。
調べたところ、Docker in Dockerには賛否両論あるようです。
ホストマシンのsocketをマウントし各コンテナで使用するように設定してあるので、今回の例だと、RailsのコンテナからJenkinsのコンテナが見えてしまうという問題があります。
しかし、

  • Dockerfileに記述すれば誰でもJenkinsの設定を変えることが出来る
  • ECSを使用して簡単にSlaveを管理出来る

という利点から今回はこのDocker in Dockerの方式を採用しました。

フロー

  1. Githubのpush or Jenkinsからの操作
  2. GithubのStatusをPendingに変更
  3. docker-compose build
  4. rubocop
  5. scss-lint
  6. slim-lint
  7. RSpec
  8. (Deployモードなら)docker build
  9. (Deployモードなら)ECRへのプッシュ
  10. (Deployモードなら)harmonik*1を使用したデプロイ

というフローになっております。
フローは4種類となり、それぞれJenkinsfileで管理するようにしています。

環境 モード
production deploy
production test
staging deploy
staging test

モードはtest・deployの2種類です。
testモードはRSpecまで(master, developブランチならば当該サーバに自動デプロイ)、deployモードはdocker build→デプロイまでを行うように設定しています。
こうすることによって、テスト無しでドッグフーディング環境にデプロイすることが出来、ビジネスサイドのチェックも素早く行うことが出来ます。

Jenkinsfile

Jenkinsfileはフェーズごとにファイルを分けました。

Jenkinsfile
Jenkinsfile.test
Jenkinsfile.build
Jenkinsfile.deploy

と言った具合です。
JenkinsfileはGroovyで記述します。

Jenkinsfile

環境やモードによってどの処理をするか、クレデンシャルの読み込み、またGithubのStatusを替えるといった処理を記述しています。

  1. Jenkinsのパラメータから環境・モードを判別
  2. Slackに開始を通知
  3. mode == ‘test’の場合、GithubのStatusをPendingに変更
  4. それぞれに必要なCredentialをS3からダウンロード
  5. deployモードならbuild, deployファイルの処理を行う
  6. testモードならtestファイルの処理を行う。master, developブランチならさらにbuild, deployファイルの処理を行う
  7. 終了通知をslackに送る

Jenkinsfile.test

testモードで使用するファイルです。主にテストやlintを回します。

  1. テストで使用するENVをS3からダウンロード
  2. docker-compose build
  3. bundle install
  4. Rubocop
  5. scss-lint
  6. slim-lint
  7. rake db:create && rake db:schema:load
  8. RSpec

Jenkinsfile.build

deployモード、またmaster・developブランチのtest終了後に使用します。 コンテナをビルドし、ECRにプッシュするところを担当しています。

  1. 各コンテナに使用するクレデンシャルをS3からダウンロード
  2. 各コンテナをビルド(タグはブランチ名+コミットハッシュ)
  3. 各コンテナをECRの各レポジトリにプッシュ

とこちらも至ってシンプルです。

Jenkinsfile.deploy

こちらは前回の記事で記述したデプロイツールのharmonik*2を使用します。

  1. バッチコンテナのデプロイ
  2. メンテナンスコンテナのデプロイ
  3. Rails関連コンテナのデプロイ

とこちらも比較的シンプルです。 Jenkinsfileを分割することにより、共通するコードをまとめることが出来、非常に見通しが良くなりました。

と弊社では上記のようにJenkinsを運用しています。 最初の設定は大変ですが、Dockerを利用することにより管理コストの削減や興味がある人間が気軽にJenkinsを設定出来るようになりました。

*1:前回の記事で紹介したデプロイツールです

*2:前回の記事で紹介したデプロイツールです