ユアマイスター株式会社エンジニアブログ

ユアマイスター株式会社のエンジニアが日々徒然。

Circle CI ビルドが遅くて仕事にならないからどうにかした話

f:id:yourmystar_engineer:20191112182902j:plain

どうも。ユアマイスター星(@inase17000)です。

おっと前の記事から1ヶ月も経ってしまった。暑い季節も過ぎ去りいつの間にか肌寒くなってきました。

今回はCircle CIまわりで問題に直面したのでその解決までの過程と、config.ymlをバージョン2.1にあげて少しリファクタリングした話を備忘のために書いておこうと思います。

ビルド時間を短縮したい

ユアマイスター では、featureブランチ、developブランチにpush(またはmerge)された時にCircle CIによってPHPUnitの自動テストを実行しています。developブランチに関しては、テスト通過後、ステージング環境へのデプロイも行なっているので、エンジニアたちにとってこのテスト時間というのは短ければ短いほど嬉しいのです。

※過去記事も貼っておきます。 yourmystar-engineer.hatenablog.jp

一方で、春先から不具合の根本対策やテストコーディングのクセづけを目的に、PHPUnitのテストコードを増やしてきました。いつかはこのビルド時間が気になることになるだろうと予想はしていましたが、思ったより早かった。。。

もともと数分で終わっていたものが、たまに1時間以上かかるビルドが現れるようになりました。エンジニアのDXが損なわれているのを看過できない!ということで解決に向けて動くのでした。

原因はカバレッジレポート生成だった

原因を調査していく中で、色々な可能性を検討しました。

  • Circle CI のビルド実行コンテナのスペックが不足していてテスト実行に時間がかかっている
  • テストの中に外部ネットワークに接続するようなコードがあり、タイムアウトエラーを繰り返している
  • そもそもテストコードに無駄が多く、時間を浪費するようなものがある
  • Circle CI の config.yml に問題がある
  • composerでインストールしている phpunitや関連モジュールのバージョンが古い などなど

エンジニアのDXに直結することを考えると、解決したらいいな案件ではなく、マスト案件なのは間違いありません。

問題の切り分けをしていく中で、ブランチによって遅くなることがあったりなかったりすることがわかってきました。 遅くなるのは、必ず、developブランチにpush(またはmerge)された時に限られました。

他のブランチとの差分を考えてみると明らかにカバレッジレートの有無で実行時間が変わっていたことが決め手です。

f:id:yourmystar_engineer:20191112180731j:plain 参考: https://circleci.com/ja/pricing/

(途中でCircle CIの実行環境のインスタンスタイプをlarge, xlargeにスケールアップしてみたものの症状は変わらなかった...)

そこで、どうするか一晩考えました。

解決策

「developブランチはbuildとdeploy、masterブランチでbuildとカバレッジレポート生成」 というように、カバレッジレポート生成のタイミングをずらすことにしました。

f:id:yourmystar_engineer:20191112181254j:plain

masterブランチにコードが入るときはつまり本番にリリースされるときなので、その頻度くらいでカバレッジレポートが確認できれば十分だという判断です。(本当は1日に1回くらいで十分なんですが)

おかげで、developブランチのプルリクmerge後〜ステージング環境デプロイまでのリードタイムがだいぶ抑えられるようになりました。

とはいえ、今後テストコードがさらに増えてきた時には、今許容できる待ち時間も辛くなってくるに違いありません。定期的に実行時間を気にしながらメンテナンスしていこうと思います。

おまけ:config.ymlのリファクタリングexecutors を使った

そういえば、今回の問題解決プロセスの中で、Circle CI(バージョン2.1以降)の便利機能を使いました。

公式ドキュメントにはこのように説明されています。

Executors は、ジョブステップの実行環境を定義するものです。executor を 1 つ定義するだけで複数のジョブで再利用できます。

つまり、今までjobごとに書いていた docker とか machine の記述を一つにまとめて命名し、それを使いまわせるという便利機能です。ユアマイスター のconfig.ymlもdockerに関して2回同じ記述があったので、この executors を利用し、コードの共通化ができました。

以前、バージョンアップ対応を、config.ymlの上の方に書いてある部分だけ修正して、下の方に書いてある方を放置してしまうといったミスがあったのですが、これで二度と起きることはありません。共通化を適切に行うことによってコードのメンテナンス性が上がりました。

以上、Circle CIの話でした。