😇

CodeBuildのローカル実行でハマった

2024/03/06に公開

はじめに

CodeBuildをローカルで動かしてみましたが、Dockerのバージョンのせいで少しハマってしまった備忘録です。

https://docs.aws.amazon.com/codebuild/latest/userguide/use-codebuild-agent.html

実施環境

Macbook Pro 2021 M1 Pro
Docker Desktop v4.28.0

やってみた

ビルドソースのセットアップ

なんでもいいですが、今回はgradleのKotlin/JVMプロジェクトをビルドしてみることにします。
gradle init でデフォルトで作成されるサンプルプロジェクトを使用します。
サンプルコードはここにおいておきます。

https://github.com/souhub/souhublabs/tree/main/codebuild-local-got-stuck

buildspec.yml は中身はなんでもいいのでとりあえずこのようにしておきます。

buildspec.yml
version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto17
  pre_build:
    on-failure: ABORT
    commands:
      - echo ビルド前の処理を書くよ
      - echo ビルドがんばろう
  build:
    on-failure: ABORT
    commands:
      - echo ビルド開始するよ
      - ./gradlew build
      - echo ビルド完了したよ
  post_build:
    on-failure: ABORT
    commands:
      - echo ビルド後の処理を書くよ
      - echo ビルドお疲れ様でした

artifacts:
  files:
    - app/build/libs/app.jar

ビルドイメージのセットアップ

今回CodeBuildで使用したいビルドイメージはこれです。(CodeBuildコンソールのスクショ)
まずは、これと同じビルドイメージをローカルでセットアップしていきます。

codebuild build image

ECRパブリックレジストリに公開されているものをpullするだけです。

set_up_build_image.sh
docker pull public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:5.0

CodeBuild Agentのセットアップ

ローカルでCodeBuildを実行するためのAgent用Dockerイメージをpullします。

X86_64とARMのどちらを使用しているかでpullするイメージが異なるため、自分のマシンがどちらか確認します。

check_local_machine_architecture.sh
uname -m


自分のマシンはarm64と出たので、ドキュメントに従いARM用イメージをpullします。

pull_codebuild_agent.sh
docker pull public.ecr.aws/codebuild/local-builds:aarch64


CodeBuild Agent実行スクリプトをドキュメントに従いダウンロードします。

move_to_build_source.sh
cd <ビルドしたいソースディレクトリ>
install_codebuild_execution_script.sh
curl -O  https://raw.githubusercontent.com/aws/aws-codebuild-docker-images/master/local_builds/codebuild_build.sh
chmod +x codebuild_build.sh

CodeBuildの実行失敗

早速実行してみます。
-i と -a は必須です。それぞれビルドイメージとアーティファクトのアウトプットディレクトリを指定します。
オプション一覧はGitHubにあるとおりです。

https://github.com/aws/aws-codebuild-docker-images/tree/master/local_builds

run_codebuild.sh
./codebuild_build.sh -i public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:5.0 -a app/build/codebuild -l public.ecr.aws/codebuild/local-builds:aarch64


実行してみたところ以下のエラーが発生しました。

error.log
ERROR: client version 1.22 is too old. Minimum supported API version is 1.24, please upgrade your client to a newer version


とりあえずdockerのバージョンを確認してみます。

check_docker_version.sh
docker version

以下のようにDocker Desktopのバージョン情報が色々でてきます。
ここに minimum version 1.24とあります。

check_docker_version_output.sh
# 一部省略
Server: Docker Desktop 4.28.0 (139021)
 Engine:
  Version:          25.0.3
  API version:      1.44 (minimum version 1.24)


2024/1/25にリリースされたDokcer Desktop 4.27.0からDocker Engineがv25にアップグレードされたことでAPIのminimum versionが変更されたことが原因のようです。

v24であれば問題ないようなので、Docker Engineのバージョンを24にダウングレードするため一度Docker Desktopを入れ直します。

[Docker Desktop release notes]を見に行くと、Docker Engine 24系を使ってる最新のDesktopのバージョンは4.26.1のようなので、それのMac Apple chip用をダウンロードします。

https://docs.docker.com/desktop/release-notes/#4261


再インストールできたのでdockerのバージョンをもう一度見てみます。

check_docker_version.sh
docker version
check_docker_version_output.sh
# 一部省略
Server: Docker Desktop 4.26.1 (131620)
 Engine:
  Version:          24.0.7
  API version:      1.43 (minimum version 1.12)

Docker Engineが24.0.7になり、API Versionがminimum version1.12となっているのが確認できました。
これでエラーは解決したはずなのでもう一度挑戦してみます。

CodeBuild の実行 再挑戦

先ほどと同様に再度実行してみます。

run_codebuild.sh
./codebuild_build.sh -i public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:5.0 -a app/build/codebuild -l public.ecr.aws/codebuild/local-builds:aarch64


今度は無事できました。このようなアウトプットが得られます。
-a app/build/codebuildで指定した通り、app/build/codebuild配下にapp.jarがアーティファクトとして保存されているのも確認できました。

output.log
Build Command:

# 省略

Removing agent-resources_build_1 ... done
Removing agent-resources_agent_1 ... done
Removing network agent-resources_default
Removing volume agent-resources_source_volume
Removing volume agent-resources_user_volume
Creating network "agent-resources_default" with the default driver
Creating volume "agent-resources_source_volume" with local driver
Creating volume "agent-resources_user_volume" with local driver
Creating agent-resources_agent_1 ... done
Creating agent-resources_build_1 ... done
Attaching to agent-resources_agent_1, agent-resources_build_1
agent_1  | [Container] 2024/03/05 14:15:35 Waiting for agent ping
agent_1  | [Container] 2024/03/05 14:15:37 Waiting for DOWNLOAD_SOURCE
agent_1  | [Container] 2024/03/05 14:15:38 Phase is DOWNLOAD_SOURCE
agent_1  | [Container] 2024/03/05 14:15:38 CODEBUILD_SRC_DIR=/codebuild/output/src531548424/src
agent_1  | [Container] 2024/03/05 14:15:38 YAML location is /codebuild/output/srcDownload/src/buildspec.yml
agent_1  | [Container] 2024/03/05 14:15:38 No commands found for phase name: install
agent_1  | [Container] 2024/03/05 14:15:38 Processing environment variables
agent_1  | [Container] 2024/03/05 14:15:38 Running command echo "Installing corretto(OpenJDK) version 17 ..."
agent_1  | Installing corretto(OpenJDK) version 17 ...
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:38 Running command export JAVA_HOME="$JAVA_17_HOME"
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:38 Running command export JRE_HOME="$JRE_17_HOME"
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:38 Running command export JDK_HOME="$JDK_17_HOME"
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:38 Running command for tool_path in "$JAVA_HOME"/bin/*;
agent_1  |  do tool=`basename "$tool_path"`;
agent_1  |   if [ $tool != 'java-rmi.cgi' ];
agent_1  |   then
agent_1  |    rm -f /usr/bin/$tool /var/lib/alternatives/$tool \
agent_1  |     && update-alternatives --install /usr/bin/$tool $tool $tool_path 20000;
agent_1  |   fi;
agent_1  | done
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:40 Moving to directory /codebuild/output/src531548424/src
agent_1  | [Container] 2024/03/05 14:15:40 Registering with agent
agent_1  | [Container] 2024/03/05 14:15:40 Phases found in YAML: 4
agent_1  | [Container] 2024/03/05 14:15:40  POST_BUILD: 2 commands
agent_1  | [Container] 2024/03/05 14:15:40  INSTALL: 0 commands
agent_1  | [Container] 2024/03/05 14:15:40  PRE_BUILD: 2 commands
agent_1  | [Container] 2024/03/05 14:15:40  BUILD: 3 commands
agent_1  | [Container] 2024/03/05 14:15:40 Phase complete: DOWNLOAD_SOURCE State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:15:40 Phase context status code:  Message: 
agent_1  | [Container] 2024/03/05 14:15:40 Entering phase INSTALL
agent_1  | [Container] 2024/03/05 14:15:40 Phase complete: INSTALL State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:15:40 Phase context status code:  Message: 
agent_1  | [Container] 2024/03/05 14:15:40 Entering phase PRE_BUILD
agent_1  | [Container] 2024/03/05 14:15:40 Running command echo ビルド前の処理を書くよ
agent_1  | ビルド前の処理を書くよ
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:40 Running command echo ビルドがんばろう
agent_1  | ビルドがんばろう
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:40 Phase complete: PRE_BUILD State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:15:40 Phase context status code:  Message: 
agent_1  | [Container] 2024/03/05 14:15:40 Entering phase BUILD
agent_1  | [Container] 2024/03/05 14:15:40 Running command echo ビルド開始するよ
agent_1  | ビルド開始するよ
agent_1  | 
agent_1  | [Container] 2024/03/05 14:15:40 Running command ./gradlew build
agent_1  | Downloading https://services.gradle.org/distributions/gradle-8.6-bin.zip
agent_1  | ............10%.............20%............30%.............40%.............50%............60%.............70%.............80%............90%.............100%
agent_1  | 
agent_1  | Welcome to Gradle 8.6!
agent_1  | 
agent_1  | Here are the highlights of this release:
agent_1  |  - Configurable encryption key for configuration cache
agent_1  |  - Build init improvements
agent_1  |  - Build authoring improvements
agent_1  | 
agent_1  | For more details see https://docs.gradle.org/8.6/release-notes.html
agent_1  | 
agent_1  | Starting a Gradle Daemon (subsequent builds will be faster)
agent_1  | Caught exception: Couldn't poll for events, error = 4
agent_1  | Error while receiving file changes
agent_1  | net.rubygrapefruit.platform.NativeException: Couldn't poll for events, error = 4
agent_1  |      at net.rubygrapefruit.platform.internal.jni.AbstractNativeFileEventFunctions$NativeFileWatcher.executeRunLoop0(Native Method)
agent_1  |      at net.rubygrapefruit.platform.internal.jni.AbstractNativeFileEventFunctions$NativeFileWatcher.executeRunLoop(AbstractNativeFileEventFunctions.java:42)
agent_1  |      at net.rubygrapefruit.platform.internal.jni.AbstractFileEventFunctions$AbstractFileWatcher$1.run(AbstractFileEventFunctions.java:154)
agent_1  | > Task :app:checkKotlinGradlePluginConfigurationErrors
agent_1  | > Task :app:processResources NO-SOURCE
agent_1  | > Task :app:processTestResources NO-SOURCE
agent_1  | > Task :app:compileKotlin
agent_1  | > Task :app:compileJava NO-SOURCE
agent_1  | > Task :app:classes UP-TO-DATE
agent_1  | > Task :app:jar
agent_1  | > Task :app:startScripts
agent_1  | > Task :app:distTar
agent_1  | > Task :app:distZip
agent_1  | > Task :app:assemble
agent_1  | > Task :app:compileTestKotlin
agent_1  | > Task :app:compileTestJava NO-SOURCE
agent_1  | > Task :app:testClasses UP-TO-DATE
agent_1  | > Task :app:test
agent_1  | > Task :app:check
agent_1  | > Task :app:build
agent_1  | 
agent_1  | BUILD SUCCESSFUL in 1m 30s
agent_1  | 8 actionable tasks: 8 executed
agent_1  | 
agent_1  | [Container] 2024/03/05 14:17:11 Running command echo ビルド完了したよ
agent_1  | ビルド完了したよ
agent_1  | 
agent_1  | [Container] 2024/03/05 14:17:11 Phase complete: BUILD State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:17:11 Phase context status code:  Message: 
agent_1  | [Container] 2024/03/05 14:17:11 Entering phase POST_BUILD
agent_1  | [Container] 2024/03/05 14:17:11 Running command echo ビルド後の処理を書くよ
agent_1  | ビルド後の処理を書くよ
agent_1  | 
agent_1  | [Container] 2024/03/05 14:17:11 Running command echo ビルドお疲れ様でした
agent_1  | ビルドお疲れ様でした
agent_1  | 
agent_1  | [Container] 2024/03/05 14:17:11 Phase complete: POST_BUILD State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:17:11 Phase context status code:  Message: 
agent_1  | [Container] 2024/03/05 14:17:11 Expanding base directory path: .
agent_1  | [Container] 2024/03/05 14:17:11 Assembling file list
agent_1  | [Container] 2024/03/05 14:17:11 Expanding .
agent_1  | [Container] 2024/03/05 14:17:11 Expanding file paths for base directory .
agent_1  | [Container] 2024/03/05 14:17:11 Assembling file list
agent_1  | [Container] 2024/03/05 14:17:11 Expanding app/build/libs/app.jar
agent_1  | [Container] 2024/03/05 14:17:12 Found 1 file(s)
agent_1  | [Container] 2024/03/05 14:17:12 Preparing to copy secondary artifacts
agent_1  | [Container] 2024/03/05 14:17:12 No secondary artifacts defined in buildspec
agent_1  | [Container] 2024/03/05 14:17:12 Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED
agent_1  | [Container] 2024/03/05 14:17:12 Phase context status code:  Message: 
agent-resources_agent_1 exited with code 0
Aborting on container exit...

おわりに

いちいちCodeBuildをAWS上で実行せずとも簡単なデバッグに使えそうでいいなとおもいました。

参考

Discussion