🏎️

AWS CodeBuild を使ったコンテナイメージビルドを Docker Build Cloud で高速化しよう

2024/12/08に公開

AWS CodeBuild を使った AWS コンテナアプリケーションのビルド

AWS CodeBuild を利用することで、コンテナアプリケーションのビルドやテストを自動化し、効率的な CI/CD ワークフローを構築することができます。また、AWS CodeBuild は AWS IAM(Identity and Access Management)と統合されており、ビルドプロセスへのアクセス権限や AWS リソースの制御をきめ細かく設定できます。

CodeBuild でビルドしたコンテナイメージは Amazon ECR に保存され、Amazon ECS や Amazon EKS にデプロイすることが可能です。さらに、これらのサービスでは ARM 系アーキテクチャを採用した AWS Graviton を利用することで、コンテナワークロードのコストパフォーマンスを向上できます。


AWS CodeBuild を使った AWS ECS への CI/CD パイプライン(ECS Workshop より)

https://aws.amazon.com/jp/builders-flash/202408/container-with-graviton/

AWS CodeBuild におけるコンテナイメージビルドの課題

AWS CodeBuild に限らず、CI パイプラインでのコンテナイメージビルドには実行時間が長くなってしまう傾向があります。これにより、以下のような影響が生じる可能性があります。

  • 開発生産性の低下
  • リリース頻度の低下
  • 障害発生時の復旧時間の延長

以下では、ビルド時間が長くなる主な原因を挙げます。

1. ビルドするマシンのスペック

一般的に、コンテナイメージのビルドには多くのリソース(CPU、RAM)が必要になります。そのため CI パイプラインで使用するマシンのスペックが不足している場合、ビルド時間が増加してしまいます。

簡単なコンテナイメージビルドではそれほど影響はありませんが、マルチステージビルドや依存関係の多いビルドでは顕著に現れます。

AWS CodeBuild ではインスタンスタイプを変更することによってこれらを改善することもできますが、コンテナイメージビルド以外の部分にも適用される他、コストも増加します。

そのため、開発者はコストとビルドスピードのバランスを考慮してパイプラインを最適化する必要があります。

2. コンテナイメージキャッシュ

ローカル開発環境では、Docker ビルドキャッシュにより再ビルドの時間を短縮することができます。

しかし、クラウド上の CI サービスでは、デフォルトでクリーンな環境が使用されるため、キャッシュを利用できず、ビルド時間が長くなってしまいます。

キャッシュを活用するためにストレージやコンテナレジストリを利用する方法もありますが、これには設定の複雑化や、キャッシュデータのアップロード・ダウンロードによるオーバーヘッドが発生してします。

3. マルチプラットフォームビルド(AMD64, ARM64)

Amazon EKS や AWS ECS で ARM 系アーキテクチャの AWS Graviton を利用するには、ARM64 対応のコンテナイメージビルドが必要です。

その他 Apple Silicon などのローカル環境の変化に伴い、AMD64 と ARM64 のマルチプラットフォーム対応が求められるケースが増えています。

しかし、異なるアーキテクチャ向けのイメージビルドにはエミュレーションが必要になることが多く、それがビルド時間の増加につながる場合があります。

AWS CodeBuild では AMD64, ARM64 インスタンスが用意されていますが、それぞれ別のパイプラインとして実行する必要があるため、設定や運用が複雑化しがちです。


https://aws.amazon.com/jp/builders-flash/202408/container-with-graviton/

Docker Build Cloud によるコンテナイメージビルドの高速化

Docker Build Cloud は Docker イメージのビルドプロセスをクラウド上で実行することで、ビルド時間を大幅に短縮し、開発者の生産性を向上させるサービスです。

特に CI パイプラインにおいては、既存のCIパイプラインを移行・大きな変更をすることなく、コンテナイメージの高速化を実現することができます。

Docker Build Cloud は以下の特徴を持っています。

1. 高性能なクラウドビルダー

16 vCPU、32GB RAM を備えたクラウドビルダーを利用可能です。

これにより、ローカル環境やリソース不足の CI サービスよりも高速なビルドが実現できます。

2. 共有キャッシュの活用

クラウドビルダーには 200 GiB の共有キャッシュが用意されており、次回以降のビルド時間を大幅に短縮することができます。

このキャッシュは設定不要で利用可能です。

3. マルチプラットフォーム(AMD64, ARM64)

Docker Build Cloud は、単一のコマンドでマルチプラットフォームへのネイティブビルドをサポートしています。

docker buildx build コマンドに --platform linux/amd64,linux/arm64 を指定するだけで ARM64 と AMD64 向けのイメージを一度にビルドすることができます。

これにより、パイプラインを分割する手間が省けます。

AWS CodeBuild + Docker Build Cloud アーキテクチャー

では実際に Docker Build Cloud を利用して AWS CodeBuild におけるコンテナイメージビルドを高速化しましょう。

アーキテクチャーとしては以下のようになります。

  1. ソースコード(AWS CodeCommit, GitHub, GitLab) から AWS CodeBuild パイプラインがトリガーされる
  2. AWS CodeBuild で Docker Build Cloud を実行する事前準備を行う(Buildx のインストール、Docker (Build Cloud)クラウドビルダーの指定)
  3. Docker Build Cloud の各クラウドビルダー(AMD64, ARM64)でコンテナイメージビルドを行う
  4. ビルドされた AMD64, ARM64 コンテナイメージを Amazon ECR へプッシュする

Docker Build Cloud をセットアップする

はじめに Docker Build Cloud のセットアップを行います。

新しい Docker サブスクリプションには既に Docker Build Cloud の無料枠が用意されています。

https://www.docker.com/ja-jp/pricing/december-2024-subscription-changes/

Docker アカウントでログインした後に Docker Build Cloud ダッシュボード にアクセスします。ここで新しいクラウドビルダーを作成することができます。

クラウドビルダーの作成に成功すると、ローカル環境(Docker Desktop, CLI)や CI/CD 環境での利用方法を確認するためのガイドが表示されます。

また、AWS CodeBuild から Docker Build Cloud を利用するためには、Docker Personal Access Token(PAT)が必要です。

https://docs.docker.com/security/for-developers/access-tokens/

このトークンを AWS Secrets Manager に保存して、安全にアクセスできるようにします。

AWS CodeBuild パイプラインをセットアップする

次に、AWS CodeBuild パイプラインをセットアップします。

事前にコンテナイメージを保存するための Amazon ECR レポジトリを用意しておきます。

今回は以下の設定で AWS CodeBuild パイプラインを作成します。

  • AMD64 3GBメモリ 2vCPU インスタンス
  • サービスロールには、Amazon ECR へのプッシュ権限と Docker Personal Access Token(PAT)を取得するための AWS Secrets Manager へのアクセス権限を付与

buildspec.yml は以下のように記述します。

version: 0.2

env:
  variables:
    ARCH: amd64
    ECR_REGISTRY: [ECR レジストリ名]
    ECR_REPOSITORY: [ECR レポジトリ名]
    DOCKER_ORG: [Docker Organization 名]
  secrets-manager:
    DOCKER_USER: ${SECRETS_NAME}:DOCKER_USER
    DOCKER_PAT: ${SECRETS_NAME}:DOCKER_PAT

phases:
  install:
    commands:
      # Buildx のインストール
      - BUILDX_URL=$(curl -s https://raw.githubusercontent.com/docker/actions-toolkit/main/.github/buildx-lab-releases.json | jq -r ".latest.assets[] | select(endswith(\"linux-$ARCH\"))")
      - mkdir -vp ~/.docker/cli-plugins/
      - curl --silent -L --output ~/.docker/cli-plugins/docker-buildx $BUILDX_URL
      - chmod a+x ~/.docker/cli-plugins/docker-buildx

  pre_build:
    commands:
      # Amazon ECR へのログイン
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
      # Docker (Build Cloud) へのログイン
      - echo "$DOCKER_PAT" | docker login --username $DOCKER_USER --password-stdin
      # クラウドビルダーの指定
      - docker buildx create --use --driver cloud $DOCKER_ORG/demo

  build:
    commands:
      # イメージタグ
      - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)
      # コンテナイメージのビルド・Amazon ECR へのプッシュ
      - docker buildx build --platform linux/amd64,linux/arm64 --push --tag "${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_TAG}" .

はじめに install phase では Docker Build Cloud を利用するのに必要な Buildx のインストールを行なっています。

AWS CodeBuild に既に Buildx がインストールされている場合もありますが、Docker Build Cloud の使用がサポートされていないバージョンの可能性もあるため、最新バージョンをインストールすることをおすすめします。

次に pre_build phase では以下のことを行なっています。

  • Amazon ECR へのログイン
  • Docker (Build Cloud) へのログイン
  • クラウドビルダーの指定

そして build phase ではイメージタグを指定した上で、コンテナイメージのビルド・Amazon ECR へのプッシュを行なっています。

この際、build と push でコマンドを分けるのではなく --push を使って直接 Amazon ECR へプッシュ することで不必要なファイル転送を回避することができ、ビルドの高速化に貢献できます。

実行結果の比較

比較するために、Docker Build Cloud を使用しない AWS CodeBuild パイプラインを作成します。

使用するインスタンスタイプは同じもの(AMD64 3GBメモリ 2vCPU)を使用し、AMD64のみのコンテナイメージビルドにしています。

また、Docker へのログインは DockerHub からの Pull Rate Limit を回避するために使用しています。

version: 0.2

env:
  variables:
    ECR_REGISTRY: [ECR レジストリ名]
    ECR_REPOSITORY: [ECR レポジトリ名]
  secrets-manager:
    DOCKER_USER: ${SECRETS_NAME}:DOCKER_USER
    DOCKER_PAT: ${SECRETS_NAME}:DOCKER_PAT

phases:
  pre_build:
    commands:
      # Amazon ECR へのログイン
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
      # Docker へのログイン
      - echo "$DOCKER_PAT" | docker login --username $DOCKER_USER --password-stdin

  build:
    commands:
      # イメージタグ
      - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)
      # コンテナイメージのビルド・Amazon ECR へのプッシュ
      - docker build --push --tag "${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_TAG}" .

実行した結果がこちらです。

次に Docker Build Cloud を使用した AWS CodeBuild のパイプラインの実行結果がこちらです。

ビルドするコンテナイメージやキャッシュの保存状況により実行結果は変わりますが、高速にコンテナイメージをビルドすることができ、かつ単一のパイプラインでマルチプラットフォームビルド(AMD64, ARM64)を実現することができました。

おわりに

AWS CodeBuild を使った CI/CD パイプラインに Docker Build Cloud を統合することで、ビルド時間を劇的に短縮し、リリース頻度を向上させることができます。これにより、開発者は生産性を最大化しつつ、ユーザーに迅速な価値提供を行うことが可能になります。

先述の通り、新しい Docker サブスクリプションには既に Docker Build Cloud の無料枠が用意されています。

別途契約する必要がなくはじめることができるため、現状のプロジェクトでどのくらいコンテナイメージビルドを高速化することができるのか是非お試しください。

Docker Build Cloud に関する情報は、私が公式ドキュメントを日本語訳しましたので併せて参考にしていただければと思います。
(最新情報は公式ドキュメントをご覧ください)
https://docs.tadashi0713.dev/build-cloud-ja

Discussion