Ruby
CI
RubyOnRails
docker
ConcourseCI

Concourse CIでRailsアプリケーションをデプロイする

概要

Concourse CIを使ってRailsアプリケーションをデプロイするデモです。
情報が少なく、色々と自分なりに工夫しました。
これがベストプラクティスなのかどうかは分かりませんが、ひとまずこれでやりたいことは実現できました。

環境

  • CentOS 7.2
  • kernel 4.12.4-1.el7.elrepo.x86_64
  • fly 3.3.4
  • docker 17.05.0-ce
  • docker-compose version 1.15.0
  • ruby2.4.1

前提条件

以下の条件を満たすようなConcourse CIを作ります。

1. ビルドキャッシュを使う

bundle installを毎回1からやると時間がかかってしまうので、キャッシュする

2. ブランチによってpipelineを分ける

stagingブランチにマージされたらstaging環境へ、productionブランチにマージされたらproduction環境にデプロイする

3. pipelineは独立させる

pipelineのファイルは、railsアプリケーションのレポジトリに入れるのではなく、独立したレポジトリで管理し、concourse-ciのサーバーに設置する

4. ビルドログの永続化(未実施)

docker-compose down すると、ビルドの履歴や、登録したpipelineなどがすべて消えてしまう

運用フロー

簡単にですが、運用フローは以下のようになります。

  1. Rails Application レポジトリのstaging、productionブランチにマージ
  2. Concourse CIが動く
    • Railsのrspecが実行される
    • Capistranoが実行されてデプロイ

サーバー構成

vagrantを使って以下の環境を構築します。
参考:Vagrantのインストール、設定手順

それぞれのサーバーには、servicesの列に書かれているソースを設置します。

hostname ipaddr services
concourse-ci 192.168.33.10
staging 192.168.33.11 Rails Application
production 192.168.33.12 Rails Application

サンプル用ソース

各種アプリケーションのソースは、githubに上げてある以下の4つのレポジトリのものを使用します。
Capistranoは、Concourse CIのdockerコンテナ内で実行するので、ホストOS上には設置しません。

GitHub repository 用途 設置するサーバー
concourse-ci Concourse CI本体 192.168.33.10
concourse-ci-pipelines Railsをデプロイするためのpipeline 192.168.33.10
rails-sample テスト用Rails Application
  • 192.168.33.11
  • 192.168.33.12
capistrano-sample テスト用Capistrano -

環境構築手順

concourse-ci(192.168.33.10)の環境構築

カーネルのバージョンアップ

Concourse CIを使うためには、kernelのバージョンは、v3.19以上である必要があります。
uname -r コマンドで、kernelのバージョンを確認して、バージョンが低い場合はアップデートをしてください。

以下に、kernelをupdateするためのシェルスクリプトを作成しました。
こちらを実行すれば、カーネルがアップデートされます。
CentOS7.2でしか動作検証していません。
https://github.com/Esfahan/kernel-updater

もし、このシェルスクリプトでアップデートできない場合は、以下を参考にしてアップデートしてください。
VagrantのCentOS7のカーネルを更新(yum)

docker-composeのインストール

こちらを参考に、docker-composeをインストールしてください。
docker(docker-engine), docker-composeのインストール

staging(192.168.33.11), production(192.168.33.12)の環境構築

こちらを参考にしてruby2.4.1をインストールしてください。
また、rails-appという名前のlinuxユーザーを作成してください。

Concourse CIの設置、設定

concourse-ciの設置

ソースの取得

Concourse CI本体のソースを取得します。

$ git clone https://github.com/Esfahan/concourse-ci

webとworkerのためのキーを作成

docker-compose.ymlがある階層で実行します。

$ mkdir -p keys/web keys/worker
$ ssh-keygen -t rsa -f ./keys/web/tsa_host_key -N ''
$ ssh-keygen -t rsa -f ./keys/web/session_signing_key -N ''
$ ssh-keygen -t rsa -f ./keys/worker/worker_key -N ''
$ cp ./keys/worker/worker_key.pub ./keys/web/authorized_worker_keys
$ cp ./keys/web/tsa_host_key.pub ./keys/worker

.envの作成

内容は適宜変更してください。

$ mv .env.example .env

CONCOURSE_BASIC_AUTH_USERNAME=管理画面にログインするためのユーザー名
CONCOURSE_BASIC_AUTH_PASSWORD=管理画面にログインするためのパスワード
CONCOURSE_EXTERNAL_URL=http://192.168.33.10:8080(管理画面のURL:8080)
CONCOURSE_POSTGRES_USER=postgresのユーザー名
CONCOURSE_POSTGRES_PASSWORD=postgresのパスワード

Concourse CIを起動

$ docker-compose up -d --build

以下のURLにアクセスすると、画面が見れるようになっているはずです。
.envでセットしたアカウントでログインしてみてください。
http://192.168.33.10:8080

CLIのインストール

Concourse CIをCLIで実行するためにflyを使います。
以下の記事を参考にしてインストールしてください。

CLIのインストール

pipelinesの設置

ソースの取得

Railsをデプロイするためのpipelineのソースを取得します。

$ git clone https://github.com/Esfahan/concourse-ci-pipelines

秘密鍵を定数にセット

pipelineでgitを扱うためと、capistranoでデプロイする際に使う秘密鍵を、以下のようにして定数にセットします。
どちらも同一の鍵を使用するので、定義する定数は1つです。

~/.concourse/credentials.yml
---
github-private-key: |
  -----BEGIN RSA PRIVATE KEY-----
  **snip**
  -----END RSA PRIVATE KEY-----

Concoures CIにログイン

Concoures CIにflyコマンドでログインします。
-tのあとの名前は、任意のものを付けてください。

$ fly -t concourse-sample login -c http://192.168.33.10:8080

ログイン成功すると、以下のコマンドでターゲットの一覧を確認できます。

$ fly targets
name          url                        team  expiry
concourse-sample  http://192.168.33.14:8080  main  Sat, 30 Sep 2017 07:33:20 UTC

pipelineの書式

長くなるので、別記事にしました。
Concourse CIのpipelineの書き方

こちらのソースの詳細な説明となります。
https://github.com/Esfahan/concourse-ci-pipelines

pipelineの書き方を知りたい場合に参考にしてください。

pipelineをConcourse CIに登録

Concourse CIは、以下の流れでデプロイを実行します。

  • pipelineをConcourse CIに登録
  • Concourse CIが定期的にレポジトリをチェックし、前回デプロイ時とソースに差分があると自動でデプロイをする
    • pause中はデプロイしないが、unpuaseにした時点で差分を検知すればデプロイが始まる(pauseについては後述

以下のコマンドでpipelineを登録します。

$ fly -t [target name] set-pipeline -p [pipelineの名前] -c concourse-ci-pipelines/rails-sample/pipelines/pipeline.yml -l ~/.concourse/credentials.yml

target nameは、login時に付けた名前、pipelineの名前は、何でもよいのですが、アプリケーションの名前を付けるとわかりやすいと思います。今回は、以下の内容で登録をします。

$ fly -t concourse-sample set-pipeline -p rails-sample -c concourse-ci-pipelines/rails-sample/pipelines/pipeline.yml -l ~/.concourse/credentials.yml

apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: http://192.168.33.10:8080/teams/main/pipelines/rails-sample

the pipeline is currently paused. to unpause, either:
  - run the unpause-pipeline command
  - click play next to the pipeline in the web ui

pipelineの図を確認

登録が完了すると、web画面で以下のようなpipelineの図が見れるようになっているはずです。
http://192.168.33.10:8080

f76a136b0286f1eb060547191c61c10b.png

黒い四角はgitレポジトリ、灰色はdockerコンテナで、
実線は、そのgitレポジトリのソースに変更があったらCIが稼働するという意味で、点線は変更があってもCI稼働のトリガーとならないものです。

デプロイ待機状態にする

このままではまだデプロイされません。
web画面の左メニューを見ると、pipelineの名前の横に、再生ボタンがあると思います。
このボタンをクリックするか、以下のコマンドを実行することで、デプロイ待機状態となり、
gitのソースに差分があることを検知すると、自動でデプロイが実行されるようになります。

コマンドでunpauseしてみます。

$ fly -t concourse-sample unpause-pipeline -p rails-sample

すると、以下のように、rails-job-stagingrails-job-productionが光りだし、デプロイが始まります。

e41b0d578360a4388a890ce0df34a41f.png

capistrano-sampleがオレンジ色になっているのは、エラーが起きているからです。
存在しないブランチ名を定義してしまっていたことが原因でした、気にしないでください。
このように、エラーが起きた場合はオレンジ色になります。

実行内容を確認

rails-job-stagingをクリックすると、以下のように、実行内容を確認できます。
以下の画像は、実行が正常終了したあとのものですが、実行中は黄色、エラー終了の場合はオレンジになります。

9200b3e9a692d20152bdf0e7d8d149e2.png

全て正常終了すると、緑になります。
これでデプロイ完了です!

5f3d2b786717cba9a3538c9f3ccf3c88.png

コマンドでも実行させることもできます。

$ fly -t concourse-sample trigger-job -j rails-sample/rails-job-staging

各種ステータス

TOPページの左下にあるように、各種ステータスの説明があります。

a56ff9225fae8ba4e809092f17db6b12.png

手動実行

実行内容詳細の画面の右上の+ボタンで、手動実行させることも可能です。

2adb06bc36bd1f13b1f14e2c67bc02e8.png

ビルドキャッシュについて

前提条件のところに書いたとおり、ビルドキャッシュを有効にしています。
その証拠に、bundle installが実行される、rails-job-stagingrails-job-productionともに、1回目より2回目以降のほうが、実行時間が短くなっています。

durationが、初回は2分51秒だったのが、2回目以降は、9秒に短縮されています。
ただし、キャッシュは、キャッシュ用コンテナで管理されているので、docker-compose downをすると、キャッシュクリアされます。

c08d9d73a7ab7f1c44a4222a58d8606a.png

4cf8108cc4107f1a0fd77bb1cb3258cd.png

同時実行数

pipelineに、max_in_flightというものを定義すると、同時実行数がセットできるみたいです。
デフォルトは1みたいです。
詳しくは以下で。
https://concourse.ci/configuring-jobs.html#max_in_flight

以上

関連記事

参考