前置き
クラウドソリューション事業部の西村です
唐突ですが、Docker Buildxでマルチアーキテクチャのイメージをビルドする際遅いなぁと思われたことはありますでしょうか?
特にコンパイル処理はかなり遅いと感じるかと思います
今回はそのような悩みをCodeBuildのバッチビルドを利用して解決したいと思います
注意事項
今回の記事ではDockerの実験的機能を利用します
ですのでこの記事を閲覧されたタイミングによっては動作しなくなる恐れもあります
予めご了承ください
バッチビルドって?
簡単に言えば複数のビルドタスクを逐次実行できたり、並列に実行させたりできます
詳しい解説は以下のドキュメントをご覧ください
AWS CodeBuild でのバッチビルドhttps://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/batch-build.html
実装
今回はコンテナイメージをビルドし、プライベートECRへプッシュするような実装をします
各ファイルの作成
以下の4つのファイルを作成します
今回の記事ではこれらのファイルをCodeCommitに入れています
Dockerfile
まずビルドに利用する簡単なDockerfileを用意します
※このDockerfileに深い意味はありません
1FROM public.ecr.aws/docker/library/php:8.1-cli
2RUN docker-php-ext-install pdo_mysql
コンテナイメージビルドを行うbuildspec
続いてコンテナイメージのビルドを行うbuildspecを作成します
ファイル名はbuild_container.ymlとしています
こちらで実行する内容はECRへのログイン、コンテナイメージのビルドとプッシュとなります
1version: 0.2
2env:
3 variables:
4 IMAGE_HOST: ''
5 IMAGE_NAME: example
6 TAG_VERSION: latest
7 TAG_SUFFIX: ''
8 DOCKER_BUILDKIT: 1
9phases:
10 pre_build:
11 commands:
12 - aws ecr get-login-password | docker login --username AWS --password-stdin $IMAGE_HOST
13 - export IMAGE_TAG="${IMAGE_HOST}${IMAGE_HOST:+/}${IMAGE_NAME}:${TAG_VERSION:-latest}${TAG_SUFFIX:+-}${TAG_SUFFIX}"
14 build:
15 commands:
16 - docker build -t $IMAGE_TAG .
17
18 post_build:
19 commands:
20 - docker push $IMAGE_TAG
マニフェストリストを作成するbuildspec
マニフェストリストを作成するbuildspecを作成します
ファイル名はcreate_manifest.ymlとしています
こちらの実行にDockerの実験的機能を利用しています
docker manifesthttps://docs.docker.com/engine/reference/commandline/manifest/
1version: 0.2
2env:
3 variables:
4 IMAGE_HOST: ''
5 IMAGE_NAME: example
6 TAG_VERSION: latest
7phases:
8 pre_build:
9 commands:
10 - aws ecr get-login-password | docker login --username AWS --password-stdin $IMAGE_HOST
11 - export IMAGE_TAG="${IMAGE_HOST}${IMAGE_HOST:+/}${IMAGE_NAME}:${TAG_VERSION:-latest}"
12 - export IMAGE_TAG_AMD64="${IMAGE_HOST}${IMAGE_HOST:+/}${IMAGE_NAME}:${TAG_VERSION:-latest}-amd64"
13 - export IMAGE_TAG_ARM64="${IMAGE_HOST}${IMAGE_HOST:+/}${IMAGE_NAME}:${TAG_VERSION:-latest}-arm64"
14 build:
15 commands:
16 - docker manifest create $IMAGE_TAG $IMAGE_TAG_AMD64 $IMAGE_TAG_ARM64
17
18 post_build:
19 commands:
20 - docker manifest push $IMAGE_TAG
メインのbuildspecを作成する
メインのbuildspecを作成します
ファイル名はbuildspec.ymlとしています
コンテナビルドに利用するイメージはそれぞれのアーキテクチャのイメージを指定しておきます
1version: 0.2
2batch:
3 fast-fail: true
4 build-graph:
5 - identifier: build_amd64
6 buildspec: build_container.yml
7 env:
8 image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
9 privileged-mode: true
10 type: LINUX_CONTAINER
11 variables:
12 TAG_SUFFIX: amd64
13 - identifier: build_arm64
14 buildspec: build_container.yml
15 env:
16 image: aws/codebuild/amazonlinux2-aarch64-standard:2.0
17 privileged-mode: true
18 type: ARM_CONTAINER
19 variables:
20 TAG_SUFFIX: arm64
21 - identifier: create_manifest
22 buildspec: create_manifest.yml
23 depend-on:
24 - build_amd64
25 - build_arm64
リポジトリの作成
続いてリポジトリを作成します
Amazon Elastic Container Registryの画面(https://console.aws.amazon.com/ecr/)を開き、”Create repository” を選択します
任意のリポジトリ名を設定し、 “Create repository” を押し作成します
作成後のリポジトリ名を覚えておくか、コピーしておいてください
CodeBuild プロジェクト作成
続いてCodeBuildのプロジェクトを作成します
CodeBuildの画面(https://console.aws.amazon.com/codesuite/codebuild/home)を開き、”Create build project” を選択します
Project configuration
Project nameに任意の名前を設定します
Source
ソースは先ほど作成したファイルを置いた場所を指定します
当記事ではCodeCommitを指定しています
Environment
イメージ関連はそれぞれ以下を選択していきます
- Operating system: Amazon Linux 2
- Image: aws/codebuld/amazonlinux2-aarch64-standard:2.0
- Image version: Always use the latest image for this runtime version
サービスロールは新規で作成します
ロール名は自動的に入っているかと思います
ここでのロール名は後ほど利用するので覚えておいてください
また追加のオプションとして環境変数を指定しておきます
- IMAGE_HOST: リポジトリ名のスラッシュより前の文字列
- IMAGE_NAME: リポジトリ名のスラッシュより後の文字列
Buildspec
そのままで問題ありません
Batch configuration
こちらの設定を行う必要があるためチェックボックスにチェックを入れます
バッチサービスロールは新規で作成します
ロール名は何かしらを入力してください
Allowed compute type(s) for batchは無くても問題ないですが念のため “3 GB memory, 2 vCPUs” を指定しておきます
※この項目はバッチで実行される処理で利用可能なコンピューティングタイプを制限できる機能です
Artifacts / Logs
そのままで問題ありません
ここまで設定できましたら “Create build project” を押し作成を行います
サービスロールにポリシーを追加する
この状態では権限がないためECRへのプッシュができません
そこで、先ほどEnvironmentで指定したロールに対してポリシーを追加します
IAMロールの画面(https://console.aws.amazon.com/iamv2#/roles)を開き、先ほど作成したロールをクリックし開きます
Add permission > Attach policies の順番に押しポリシー選択画面を開きます
“AmazonEC2ContainerRegistryPowerUser” を選択し “Attach policies” を押します
CodeBuildを実行し動作を確認する
これで準備が整ったため実行します
CodeBuildの画面へ戻り “Start build” を押し完了するまで待ちます
完了後ECRの画面へ行き、作成したリポジトリに
- latest
- latest-amd64
- latest-arm64
の3つのイメージができていれば成功です
イメージを利用する際は “latest” を利用すればOKです
比較
Buildxで実行するのとどちらが早いか気になっている方もいるかと思います
そこで比較を行ってみました
比較に利用したBuildx用のbuildspec.ymlは以下になります
1version: 0.2
2env:
3 variables:
4 IMAGE_HOST: ''
5 IMAGE_NAME: example
6 TAG_VERSION: latest
7 DOCKER_BUILDKIT: 1
8phases:
9 install:
10 commands:
11 - mkdir -p $HOME/.docker/cli-plugins
12 - curl -L "https://github.com/docker/buildx/releases/download/v0.9.1/buildx-v0.9.1.linux-arm64" -o "$HOME/.docker/cli-plugins/docker-buildx"
13 - chmod +x "$HOME/.docker/cli-plugins/docker-buildx"
14 - docker buildx create --use
15 - docker run --privileged --rm tonistiigi/binfmt --install amd64,arm64
16 pre_build:
17 commands:
18 - aws ecr get-login-password | docker login --username AWS --password-stdin $IMAGE_HOST
19 - export IMAGE_TAG="${IMAGE_HOST}${IMAGE_HOST:+/}${IMAGE_NAME}:${TAG_VERSION:-latest}"
20 build:
21 commands:
22 - docker buildx build -t $IMAGE_TAG --platform linux/arm64,linux/amd64 --push .
それ以外のファイルはそのままにしています
CodeBuildに関してはそのままでは実行できないため、バッチビルドの設定を削除したものを用意し実行しました
それぞれ5回実行した結果が以下になります
バッチビルド
- 3:44
- 3:37
- 3:50
- 4:59
- 3:32
Buildx
- 4:38
- 4:36
- 4:38
- 4:32
- 4:41
今回Dockerfileの中身がほぼなかったため、差は大きく生まれませんでした
ですがバッチビルドの方が基本的には早かったです
実際はもっと内容があるためさらに差が生まれると思います
最後に
Dockerイメージはlinux/arm64を利用することが増えてきましたが、linux/amd64もまだまだ現役で、どちらも使えないと困ることもあり作ってみました
この記事が少しでも参考になればうれしいです
最後までお読みいただきありがとうございました