プライベートリポジトリの CI 無料でお馴染みの wercker が、先日ワークフロー機能 Wercker Workflows をリリースしました。
とりあえず、以下の公式デモ動画を観れば何ができるのかわかると思います。
ブログ記事 Introducing Wercker Workflows
デモ動画 Wercker Workflows - YouTube
Wercker Workflows とは
いわゆるワークフロー機能というやつで、1つの CI プロセスを複数のパイプラインに分割して組み合わせる機能です。Jenkins とか、最近だと Concourse CI でお馴染みの機能です。
パイプラインは従来の build
, deploy
に相当するもので、1つの CI プロセス内におけるタスクの分割単位となります。従来は build
, deploy
の2つしか記述できなかったところ、test
や push-dev
のように複数種類のパイプラインを記述できるようになったのが今回の Workflows です。
以下の例では、Build
, Tests
, Push to registry
, Notify Scheduler
の4つのパイプラインを直列に実行しています。これだけだと従来の wercker とあまり変わりません。
image from: http://wercker.com/workflows/
Workflows では、複数のパイプラインを__並列に__実行することができます。以下の例は、ビルド後に開発用 (dev) イメージの push & deploy と本番用 (release) イメージの push & deploy を並列に実行しています。
image from: http://wercker.com/workflows/
それぞれのタスクは、__個別に abort & restart することが可能__です。例えば build
-> test1
-> test2
の CI プロセスが組まれている場合、従来だと test2
だけやり直したい時も最初の build
から restart させる必要がありました。Workflows では、以下のように test2
だけやり直すことが可能となります。
image from: http://wercker.com/workflows/
この Workflows、プライベートリポジトリに対しても__無料__で使うことができます。相変わらず太っ腹ですね…
Workflows を使ってみよう
実際に Rails アプリの CI を Wercker Workflows を使って実行してみましょう。
今回のチュートリアルに用いるサンプルリポジトリです: https://github.com/dtan4/rails-wercker-workflows
wercker ページです: https://app.wercker.com/#applications/57397bbed99505465708deb7
wercker.yml
いきなりですが、wercker.yml
は以下のようになります。
box:
id: quay.io/dtan4/rails-test-base
tag: latest
registry: quay.io
services:
- postgres:9.4
build:
steps:
- bundle-install
rspec-models:
steps:
- bundle-install
- script:
name: Set POSTGRES_USER
code: export POSTGRES_USER=postgres
- script:
name: Prepare database
code: bundle exec rake db:test:prepare
- script:
name: Run RSpec
code: bundle exec rspec spec/models
rspec-controllers:
steps:
- bundle-install
- script:
name: Set POSTGRES_USER
code: export POSTGRES_USER=postgres
- script:
name: Prepare database
code: bundle exec rake db:test:prepare
- script:
name: Run RSpec
code: bundle exec rspec spec/controllers
rspec-features:
steps:
- bundle-install
- script:
name: Set POSTGRES_USER
code: export POSTGRES_USER=postgres
- script:
name: Prepare database
code: bundle exec rake db:test:prepare
- script:
name: Run RSpec
code: bundle exec rspec spec/features
ベースの Docker image として、quay.io/dtan4/rails-test-base:latest を使っています。このイメージは公式の ruby:2.3.0
イメージを元に Node.js や PhantomJS をインストールしたものです。Dockerfile
はリポジトリルートに置いてあるやつです: https://github.com/dtan4/rails-wercker-workflows/blob/master/Dockerfile。
ベースイメージを ruby:2.3.0
にして都度 apt-get install
するようにしてもよいのですが、apt-get install
の結果はキャッシュされず毎回走ることになるので、時間短縮のためにキャッシュの効く Docker image に前もって含めるようにしています。
データベースは PostgreSQL を使うので、services
に postgres:9.4
を指定して PostgreSQL 9.4 のコンテナを立ち上げるようにしています。Elasticsearch とか Redis も必要であれば指定できます。
services
のコンテナは__各パイプラインにつきそれぞれ1個ずつ立ち上がる__ので、パイプライン間でデータベースアクセスの競合が起こるようなことはありません。便利。
この wercker.yml
では、以下の4つのパイプラインを定義しています。
-
build
: GitHub push を受けて最初に実行されるパイプライン -
rspec-models
:spec/models
のテスト -
rspec-controllers
:spec/controllers
のテスト -
rspec-features
:spec/features
のテスト
注意したいのは、テストのパイプラインそれぞれが bundle install
を実行している点です。最初の build
パイプラインで bundle install
を実行し、その結果をテストのパイプラインで利用すればいいと思われるかもしれません。しかし、どうやらキャッシュディレクトリである WERCKER_CACHE_DIR
は各パイプラインで独立に設定されているらしく、テストのパイプラインで build
パイプラインの結果を利用することができませんでした。
なので、初期化処理の類は各パイプラインでそれぞれ実行する必要があります。おそらく、git clone
したコードベース上で各パイプラインの Docker コンテナが走っているだけなんだと思います。
上の例だと build のあとに push が走っているので、別にパイプライン間共有のディレクトリがあるんだと思いますが…
wercker の設定
まずアカウントを取得し、https://app.wercker.com/#applications/create からリポジトリを登録します。
次に、アプリの画面で "Manage Workflows" をクリックし
ワークフローの登録と連携を行うページに飛びます。Pipelines には、デフォルトで GitHub/Bitbucket push がトリガーとなる build
パイプラインが設定されています。
"Add new pipelines" からパイプラインを登録します。
"Name" には wercker 上で表示されるパイプライン名、"YML Pipeline name" には wercker.yml
に記述したパイプライン名を入力します。
"Hook type" はこのパイプラインのトリガーを指定します。以下の2種類から選べます。
-
Default
: 他のパイプラインの成功をトリガーにする(従来のdeploy
) -
Git push
: GitHub/Bitbucket への push をトリガーにする(従来のbuild
)
"Create" するとパイプラインの個別設定ができます。
パイプライン独自の環境変数を設定できたりします。
また、"Report to SCM" にチェックを入れておくと GitHub の Pull Request 画面にパイプラインの実行結果を反映できます。イメージこんな感じです。壮観。
全部登録するとこんな感じになります。
次に、このパイプラインを組み合わせてワークフローを構築します。build
の後ろにある "+" をクリックすると、後に続くパイプラインを追加できます。特定のブランチのみ実行するようにもできます。
なお、1つのワークフロー上では同じパイプラインは1回しか使えません。
全部登録するとこうなります。テストのパイプラインは並列実行するようにしました。
これで wercker の設定は終わりです。
テスト実行
git push
すると CI が走り始めます。こんな感じでブラウザに進捗が表示されます。
並列に記述してあるパイプラインは、同時にスタートするようになっていません。従来のビルドと同じように各パイプラインもキューに突っ込まれ、適宜デキューして実行しているようです。
各パイプラインをクリックすれば、そのパイプラインの詳しい進捗を確認できます。この画面は従来の wercker と同じですね。このページからパイプラインの abort や restart を行うことができます。
https://app.wercker.com/#dtan4/rails-wercker-workflows/rspec-controllers/57398ba39779f5075802a86
全部のパイプラインが成功すればこうなり、
どれか一つ失敗すればこうなります。この rspec-models
パイプラインが通信エラーのように気まぐれで失敗していた場合は、これだけ個別に再実行することができます。
トータルの実行時間がひと目でわからないのは厳しいですね…
並列実行の効果
今回はテストを3分割し並列に走らせましたが、直列に実行した場合に比べ1分程度早く終了することが確認できました (1m23s vs. 2min30s)。前述したようにパイプラインの実行タイミングに差があるので、思ったほど実行時間が短くなるわけではありません。しかし、コンテナレベルで環境が分離されるので他の同時実行しているテストの影響を受けにくいこと、各テストを個別にリスタート可能になるといった利点があるので、前向きに Workflows による並列実行を取り入れていっても良さそうです。
おわりに
Wercker Workflows の紹介と実際に Rails アプリの CI に使ってみる例を紹介しました。
wercker 社は今年の2月に資金調達してますし、有料の VPC プランも作られるなど活動が盛んになってきています。今後の進化にも期待したいところです。