ROBOT PAYMENT TECH-BLOG

株式会社ROBOT PAYMENTのテックブログです

コンテナイメージのビルド時間の変化を振り返ってみた

こんにちは。SRE課の trunkatree です。
請求管理ロボ のシステムはコンテナベースで構築していますが、今回はここ半年ほどのコンテナイメージのビルド時間の変化について振り返ってみたいと思います。

背景

請求管理ロボSREチームは現在、本番環境/検証環境のAWSアカウントを分離してマルチアカウント戦略を実現することをメインに仕事を進めています。その中で、ビルド時間の改善が見込めることもついでに取り組んできました。ビルド時間の改善を主目的として取り組んだわけではないので、その後の変化については肌感でしか確認していなかったのですが(計測せよ!)、今回のブログ執筆を良い機会と思って改めて振り返ってみたいと思います。

集計結果

早速ですが集計した結果は次のようになりました。全体としては若干ですが短縮傾向と言えそうです。 コンテナイメージのビルド環境にはCodeBuildを利用しており、実行者はその開始から終了までを待つことになるのでCodeBuildの実行時間で集計しています。横軸にはビルド実行1件1件を時系列順に並べており、縦軸は実行時間となっている棒グラフです。データセットはSUCCEEDED終了した実行のみとし、またグラフの見やすさを優先するために極端な外れ値は除外しています(3件程度です)。

  • CodeBuildの実行時間(duration = endTime - startTime)

duration

  • CodeBuildのビルドフェーズのうち PRE_BUILD, BUILD, POST_BUILD を抜粋(積み上げ棒グラフ)
    • 縦軸の単位: 秒

PRE_BUILD,BUILD,POST_BUILD

データセットは、昨年2022年10月から本ブログ執筆中の2023年6月までのデータとなっています。2022年下半期は冒頭でお伝えしたAWSアカウント分離という目標に向けてCI/CDパイプラインのマルチアカウント対応に取り組んでいました。これまでは Jenkins + CodeBuild でパイプラインを構築していましたが、AWSリソースは環境間で使い回しており、このままではAWSアカウントをまたいだ設定が必要になってくるため改善を検討しました。結果として、JenkinsはCodePipelineに置き換え、CodePipeline + CodeBuild となったパイプラインはTerraformで定義し、環境毎に独立してプロビジョニングするようにしました。

このような取り組みの中で、ビルド環境(CodeBuild)が環境毎に用意されたのが2022年10月頃で、それ以前のデータを集計しようとすると少々難易度が上がるので、今回はそれ以降のデータで集計しています。

「ビルド → DBマイグレーション → デプロイ」等の各処理をそれぞれ個別のCodeBuild Projectで実行しており、これらをCodePipelineでフロー化しています。今回の集計は「ビルド」処理のCodeBuildの実行時間を集計しています。また、CodeBuildにはビルドフェーズという実行ステップの概念がありますが、PRE_BUILDフェーズでは処理に必要なツール等のインストール、BUILDフェーズでは主に docker build、POST_BUILDフェーズでは主に docker push をしています。

変更点とビルド時間の変化

それでは、ビルド時間に影響がありそうな改修と実際の変化を照らし合わせながら集計結果を振り返ってみます。下記の他にも、インストールしているパッケージのバージョン更新などはありましたが、実行時間への影響は軽微そうだったので紹介は省略しています。

ビルド済みの場合はビルド処理をスキップ

2022年12月上旬、指定したバージョンのソースコードからコンテナイメージがビルド済みであった場合はビルド処理をスキップするようにしました。その結果、スキップとなった際にはPRE_BUILDフェーズのみが残って、BUILD, POST_BUILDフェーズは0秒(スキップ)となり、グラフが歯抜けのように変わりました。

skip

これまではアプリケーションコードに変更がなくても、パイプラインを動かす度にイメージをビルドしてコンテナレジストリ(ECR)にpushしていました。このやり方では下記のような問題があったため、CI/CDパイプラインに手を付けたついでに改善に取り組みました。

  • コンテナイメージの一意性が失われており、バージョン管理の観点でリスクがある
  • アプリケーションに変更がなくてもわざわざビルドし直しているので余計な時間/コストがかかっている

ビルドする前にイメージの存在を確認して、ビルドするかどうかを判断する制御を入れました。ビルド処理自体の変化ではないですが、パイプライン実行者(開発者)の体験は多少変わったのではないかと思っています。

GPG keyをアップデート

2023年1月下旬、PRE_BUILDフェーズにGPG keyをアップデートする一文を追加しました。2つ目のグラフは、1つ目のグラフから PRE_BUILD フェーズのみを抜き出したものです。少しだけ上昇したでしょうか。

GPG

GPG_PRE

詳しい内容はリンクのIssueを参考にしていただければと思いますが、とりあえずビルドを通すために必要となった処置です。こういう地味な保守作業、なかなか避けられないですよね。

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

github.com

CodeBuild実行環境のイメージを最新化&ローカルキャッシュ機能を有効化

2023年2月中旬、CodeBuild実行環境のイメージを最新化したのと、CodeBuildのローカルキャッシュ機能を有効化しました。イメージは aws/codebuild/docker:18.09.0 から aws/codebuild/standard:6.0 に更新し、PRE_BUILDフェーズからAWS CLIのインストール処理を削除しました。これらは同じタイミングでリリースしたのでまとめて書いています。

image

image_PRE

image_BUILD

以前は数あるCodeBuild Projectで使用しているイメージがバラバラな状況で、コードでリソース管理もしておらず、メンテナンスしづらいという課題がありました。先述のCI/CDパイプラインのTerraform化に取り組んだことで、やっとラクにCodeBuild Project群を統率できるようになったので、イメージの整理と最新化に取り組みました。また、これに合わせて簡単に改善できそうなことはついでに取り組むこととし、ローカルキャッシュ機能を有効化したり、AWS CLIのインストール処理を削除したりしました。これまではPRE_BUILDフェーズでAWS CLIをわざわざインストールしていたのですが、新しいイメージではプリインストールされており、明らかに不要だとわかっていたためこのタイミングで削除しました。

ローカルキャッシュ機能について、我々のユースケースではそこまで連続的にCodeBuildを実行することはないので、キャッシュが効いて時間短縮につながる場面はあまりないかなという見立てでしたが、副作用も特になさそうだったので有効化しました。

グラフを見ると、BUILDフェーズは短縮していますが、PRE_BUILDフェーズは長くなっていますね。全体としてはほんの少し減少傾向でしょうか。

改めて不要となった処理を削除

2023年3月下旬、改めてbuildspec.ymlに記載している処理を確認し、不要なものを削除しました。

remove

remove_PRE

2月中旬にCodeBuild実行環境のイメージを最新化したことで、これまで古いイメージのまま動かし続けるためにわざわざ入れていた処理を削除することができるようになったので、忘れないうちにキレイにしておきました。前述の通り、AWS CLIのインストール処理については明確に不要とわかっていたため先に削除しましたが、その他の処理についてはこのタイミングで改めて確認しました。結果として、PRE_BUILD フェーズから

  • 前述のGPG keyのアップデート処理を削除
  • apt-get updateapt-get install -y hoge fuga ... 処理を削除

を実施しました。グラフを確認すると、PRE_BUILD のベースラインが下がっています。

終わりに

今回はコンテナイメージのビルド時間に着目して変化を振り返ってきました。実施してきたことは、"CodeBuildをTerraform化して変更へのハードルが下がったのでいろいろとキレイにした" という保守作業やボーイスカウトルールのようなものですが、結果的にビルド時間も改善できていてよかったです。古くなった実装を放置せず、負債にならないようにちゃんと更新しておくことは将来コードを見る誰か(自分自身を含む)の時間をsaveすることにつながりますし、今回の場合はビルド時間も短縮できていることがわかりました。アップデートを怠らずにシステムのベースラインを上げ続けることの大切さを感じます。

補足ですが、今回の改善は "ついで" のスタンスで取り組んできたことなので、あまり深入りせずにできる改善にとどめています。ビルド時間の短縮を主目的とするならば、Dockerfileの改善やCodeBuild実行環境イメージの事前作成など、考えられることはいろいろありそうです。

さらに余談ですが、なにかの処理時間の改善に取り組む際は、その効果についてしっかり意識して取り組むのがよいと思っています。例えば、Webのレスポンスタイムであれば1秒なら十分早いのではという話があります。(この例はテキトーですが)1.5秒を1秒にするのと1秒を0.5秒にするのとでは効果が異なるかもしれません。はたまた、カップラーメンの待ち時間が3分に設定されているのは人間がイライラせずに待てる時間の限界が3分であるからという話があります。5分を4分にするのと4分を3分にするのとでは効果が異なるかもしれません。現状が5分であれば、3分まで改善しない限り効果は薄いかもしれません。

今回のビルド時間の改善について言えば、おそらく効果があるほどの改善にはなっていないだろうと思います。なのでやはり "ついで" 程度の結果ではあったかなと思いました。取り組んだ意義は前述のとおり負債を残さないという点にあると思います。

それではまたお会いしましょう。



We are hiring!!

ROBOT PAYMENTでは一緒に働く仲間を募集しています!!!

speakerdeck.com
www.robotpayment.co.jp
🎉twitter採用担当アカウント開設!🎉どんどん情報発信していきます!!