真似しちゃいけないdeployステップの使い方
これはCircleCI Advent Calendar 2019の8日目の記事です。
こんにちは、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は次のような感じになります。
# .circleci/config.yml version: 2.1 jobs: build: docker: - image: circleci/ruby parallelism: 4 # 4並列で実行 steps: - checkout - run: bundle install - run: # circleciコマンドを使ってテストを4分割して実行 name: Parallel Testing command: bundle exec rspec $(circleci tests glob spec/**/*.rb | circleci tests split) - deploy: # テストが通ったらデプロイ。このステップは4つのノードのうち0番目でだけ実行される name: Deploying to dev env command: bundle exec cap dev deploy
つまり、deploy
ステップを使うとCircleCIのジョブの中で並列処理の待ち合わせができるんです!
待ち合わせ処理を書いてみる
並列実行している処理の待ち合わせが書けるなら、あとはデータの受け渡しができれば、もう並列処理のプログラム書けるようなもんだよね? 例えば、大きな処理の分割実行とその結果の統合が1つのジョブの中で済ませられるのでは?と考えてやってみました。
deploy
ステップで並列実行の待ち合わせをして、各ノードの結果をCircleCIのキャッシュ経由で受け渡しするサンプルは次のとおりです。
# .circleci/config.yml version: 2.1 jobs: build: docker: - image: circleci/node:12 parallelism: 4 steps: - checkout # 成果物を result-{ノード番号}.txt に保存する、ビルドとかテスト実行など並列実行したい遅い処理 - 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"] } # 0番目のノードで他ノードの成果物を組み合わせる - 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。