これはCircleCI Advent Calendar 2019の8日目の記事です。
qiita.com
こんにちは、CircleCI大プッシュしてたらCircleCIの回し者だと思われた@mstsskです。
今回はdeploy
ステップの変な使い方を思いついたので紹介します。
ただし、真似しちゃいけません。
deploy
ステップについて
CircleCIでは、CIジョブで実行するコマンドのステップをrun
というキーワードで記述します。
そして実はdeploy
というキーワードでもコマンドを記述できるようになっています。
deploy
ステップの書き方はrun
と同じですが、文字通りデプロイのためのステップであり、動作が異なります。
parallelism
を使ったジョブの場合、deploy
ステップは他のすべてのノードが成功した場合にのみ、ノード番号 0 として実行されます。 ノード番号 0 以外はステップを実行しません。
引用元: https://circleci.com/docs/ja/2.0/configuration-reference/#deploy
deploy
ステップを使ったconfig.ymlは次のような感じになります。
version: 2.1
jobs:
build:
docker:
- image: circleci/ruby
parallelism: 4
steps:
- checkout
- run: bundle install
- run:
name: Parallel Testing
command: bundle exec rspec $(circleci tests glob spec/**/*.rb | circleci tests split)
- deploy:
name: Deploying to dev env
command: bundle exec cap dev deploy
つまり、deploy
ステップを使うとCircleCIのジョブの中で並列処理の待ち合わせができるんです!
待ち合わせ処理を書いてみる
並列実行している処理の待ち合わせが書けるなら、あとはデータの受け渡しができれば、もう並列処理のプログラム書けるようなもんだよね?
例えば、大きな処理の分割実行とその結果の統合が1つのジョブの中で済ませられるのでは?と考えてやってみました。
deploy
ステップで並列実行の待ち合わせをして、各ノードの結果をCircleCIのキャッシュ経由で受け渡しするサンプルは次のとおりです。
version: 2.1
jobs:
build:
docker:
- image: circleci/node:12
parallelism: 4
steps:
- checkout
- run:
name: Building Some Results
command: |
mkdir results/ &&
./dummy_slow.sh > results/result-$CIRCLE_NODE_INDEX.txt
- save_cache:
key: results-{{ .BuildNum }}-{{ .Environment.CIRCLE_NODE_INDEX }}
paths:
- results/
- deploy:
name: Waiting Results
command: ":"
- restore_cache: { keys: ["results-{{ .BuildNum }}-1"] }
- restore_cache: { keys: ["results-{{ .BuildNum }}-2"] }
- restore_cache: { keys: ["results-{{ .BuildNum }}-3"] }
- deploy:
name: Merging Results
command: |
ls results/
echo
cat results/result-*.txt
restore_cache
のところがどうしても冗長な書き方になりますが、これで1つのジョブの中で並列実行した結果を統合できます。
もうちょっとconfig.ymlを整理したサンプルは↓。
https://circleci.com/gh/mstssk/circleci-deploy-step-play
github.com
何に使うの?
もともとは、並列テストのカバレッジデータをサクッと統合したいと思ってなんとかジョブの中でミニマムに解決できないかと考えて思いついたものです。
実際にジョブの中でデータ集めができることを確認したあたりで正気に帰りました。
本来の使い方とは違うやり方だけど試行錯誤してなんとかなったぜやったぁ状態になる瞬間ってたまにありますよね。
よっぽど1つのジョブの中で完結させたい理由がもしあったなら使えるテクニックかもしれませんが、本当に必要かどうか3回考えてから諦めましょう。
普通に別ジョブにしてpersist_to_workspace
でデータ受け渡してやりましょう。
カバレッジデータの統合をしたい場合は、各カバレッジツールがCircleCIの場合の使い方サンプルを公開してたりしますし、Coverallsは結果をよしなにマージしてくれる機能があるらしいです1。