アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

AWS CodeBuildのDocker レイヤーキャッシュのハマったこと

こんにちは、キエンです。

現在、いこレポにてCodeBuildを使用してDockerイメージのビルドや自動化テストなどを実行しています。 開発効率を上げるため、CodeBuildの実行時間を改善しようと思っています。一つの改善案としてDocker レイヤーキャッシュを使用することです。

AWS CodeBuildのローカルキャッシュを試してみる

AWS CodeBuildのローカルキャッシュってとは

docs.aws.amazon.com

今年2月にCodeBuildのローカルキャッシュ機能が公開されました。ローカルキャッシュの特徴は

  • ビルドホストのみが利用できるキャッシュをそのビルドホストにローカルに保存する
  • キャッシュはビルドホストですぐに利用できる
  • 大規模な中間ビルドアーティファクトに適当する
  • ビルドパフォーマンスはネットワーク転送時間の影響を受けない
  • 3つのキャッシュモードがあり( 1 つ以上選択する必要ある)
    • Docker レイヤーキャッシュ
    • ソースキャッシュ
    • カスタムキャッシュ

Docker レイヤーキャッシュを実際に試してみる

対象ビルドプロジェクト

  • 自動化テスト実行のビルドプロジェクト
    • ECRからDockerイメージをプルする
    • コンテナを立ち上げて、Rspecを実施する
  • Dockerイメージビルドのビルドプロジェクト
    • Dockerイメージをビルドする
    • ECRにプッシュする

アーティファクト設定

f:id:kien4c:20190706200226p:plain

結果

  • 自動化テスト実行のビルドプロジェクト

    • 設定前 f:id:kien4c:20190706202525j:plain

    • 設定後 f:id:kien4c:20190706202541j:plain 設定後、2回目の実行にDockerイメージのプルはローカルキャッシュから使用するようになって、2分を減らせました。たったの 簡単設定ですぐに効果が出ていますね。

  • Dockerイメージビルドのビルドプロジェクト

    • 設定前 f:id:kien4c:20190706202553j:plain

    • 設定後 f:id:kien4c:20190706202606j:plain これはスゴイですね。設定後、2回目の実行に6分34秒から23秒になりました。完全に改善できそうですね。ただが。。。

    • 一時間後、再実行 f:id:kien4c:20190706202752j:plain f:id:kien4c:20190706202803j:plain 一時間後、もう一度やってみたら、ローカルキャッシュを使用できなくなって、設定前の状態に戻りました。次のビルドはまたローカルキャッシュを使用できるようになります。

=> ローカルキャッシュはビルド後一時的のみ使用できるそうです。

結論

  • 設定が簡単、すぐに使える
  • Dockerのイメージのプルやビルドする際の高速化が望める
  • ローカルキャッシュはビルド後一時的のみ使用できる
  • 希薄なビルドを実行している場合は、利点が得られない

いこレポで自動化テストのビルドは一日中でよくやっているため、AWS CodeBuildのDocker レイヤーキャッシュを使用すると効果が出ています。 一方、Dockerイメージビルドのビルドは希薄に実行しているので、利点が得られないです。

Dockerイメージビルドする時--cache-fromの使用を試してみる

最近、Dockerイメージのビルド高速化といえば、BuildKitがよく聞かれていますね。 BuildKit使用する、使用しないの場合、--cache-fromの使用方が異なるため、BuildKitもちょっとお話したいと思います。

BuildKitってとは

dev.classmethod.jp

BuildKitは次世代高速コンテナビルドで以下の特徴があり

  • Dockerfileの各ステージを並列実行できる
  • コンパイラやパッケージマネージャのキャッシュを使える
  • AWSやSSHなどの鍵を安全に扱える
  • Dockerfile以外の言語も使える(Buildpackesなど)
  • root権限無しで実行できる
  • 最新のDockerなら、export DOCKER_BUILDKIT=1するだけですぐに使える

BuildKitはすごいと思いますが、いこレポのDockerイメージは複数ステージではないのでBuildKitを使用してもあまり効果が出ていません。

サポートDockerバージョン

サポートバージョン
--cache-from 17.09以上
BuildKit 18.09以上

BuildKitを使用なしで--cache-fromを付けるDockerビルドを試してみる

buildspec.ymlの変更

現在の buildspec.yml

version: 0.2

phases:
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
  build:
    commands:
      - docker build -t ${IMAGE_REPO_NAME}:base -f ./config/docker/Dockerfile-rails-base 
  post_build:
    commands:
      - docker push ${REPO_DOMEIN}/${IMAGE_REPO_NAME}:base

buildspec .ymlを以下のように書きます。

  • イメージビルドする前にECRから前回にビルド済みのイメージをプルする
  • イメージビルドする時、--cache-fromを付けると、pre_buildでプルしたイメージをキャッシュとして使用して新規のイメージをビルドする
version: 0.2

phases:
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email --region ap-northeast-1)
      # ECRから前回にビルド済みのイメージをプルする
      - docker pull ${REPO_DOMEIN}/${IMAGE_REPO_NAME}:base || true
  build:
    commands:
      # --cache-fromを付けると、pre_buildでプルしたイメージをキャッシュとして使用して新規のイメージをビルドする 
      - docker build --cache-from ${REPO_DOMEIN}/${IMAGE_REPO_NAME}:base -t ${IMAGE_REPO_NAME}:base -f ./config/docker/Dockerfile-rails-base 
  post_build:
    commands:
      - docker push ${REPO_DOMEIN}/${IMAGE_REPO_NAME}:base

結果

f:id:kien4c:20190706202826j:plain

ビルドコストは6分33秒から1分50秒になりました。数時間後再実行しても効果が出ていますね。嬉しいです。

f:id:kien4c:20190706200522p:plain ビルドのログでUsing Cacheが表示すれば成功ですね。

今回の実験は効果を見えましたが、イメージプルのコストとイメージビルドのコストからキャッシュを使用する価値があるかどうか考えた方が良いと思います。 データ量だけ多くてイメージ等、逆に遅くなることもあります。

BuildKitを使用ありで--cache-fromを付けるDockerビルドを試してみる

環境変数はDOCKER_BUILDKIT=1をしてから、「BuildKitを使用なし」場合の通りにもう一度やってみます。

f:id:kien4c:20190706200553p:plain

残念ですが、今回エラーが出ていました。

調べてみたら、BuildKitを使用するとキャッシュフォーマットが異なるため、直接--cache-fromを使用できません。 その代わり、buildctl build --export-cacheする必要がありそうです。 github.com

ちなみに、BuildKitを使用する場合、--cache-fromを使用するため、現時点で以下のことをする必要があります。

  • buildctlをインストールする (buildkit Github)
  • buildctl build --export-cacheを使用して、イメージのキャッシュをエクスポートする
# --export-cache options
# mode=min (default): only export layers for the resulting image
# mode=max: export all the layers of all intermediate steps
# ref=docker.io/user/image:tag: reference for registry cache exporter
# dest=path/to/output-dir: directory for local cache exporter

buildctl build --export-cache ${REPO_DOMEIN}/${IMAGE_REPO_NAME}:base
  • export-cacheが完了したら、これでdocker build --cache-from を使えるようになる

まとめ

  • AWS CodeBuildのローカルキャッシュ
    • 設定が簡単、すぐに使える
    • Dockerのイメージのプルやビルドする際の高速化が望める
    • ローカルキャッシュはビルド後一時的のみ使用できる
    • 希薄なビルドを実行している場合は、利点が得られない
  • Dockerイメージビルドする時--cache-fromを付ける
    • ポイントは:
      • イメージビルドする前にECRから前回にビルド済みのイメージをプルする
      • イメージビルドする時、--cache-fromを付けると、pre_buildでプルしたイメージをキャッシュとして使用して新規のイメージをビルドする
    • Dockerのイメージのビルドする際の高速化が望める
    • イメージプルのコストとイメージビルドのコストからキャッシュを使用する価値があるかどうか判断が必須
      • データ量だけ多くてイメージ等、逆に遅くなることもある
    • BuildKitを使用する場合、直接--cache-fromを使用できない、buildctl build --export-cacheをする必要あり

最後に

アクトインディではエンジニアを募集していますね、ぜひご応募してください。 actindi.net