Header image

クラッソーネの開発者がエンジニアリングに関することもそうでないことも綴っています!

AWS CodeBuildのローカル実行

AWS CodeBuildのローカル実行

こんにちは。お盆休みは子ども経由で手足口病にかかり、両手足の指全体に水疱ができて2日ほど寝たきり生活を送っていた小木です。おかげでウォッチリストの消化が捗りました。
この歳まで風邪すらまともにかかったことのないのが自慢だったのですが、寄る年波には勝てないのか、それとも保育園経由でかかる病気が強力なのか。。

・・・・

と、夏の終わりに書いた記事を放置していて今になってやっと整備しました。

はじめに

さて、前回はAmplifyのマニュアルビルドの方法について調べました。
これはAmplifyを既存のCodePipelineに組み込むためでしたが、ではCodePipelineにどうやって組み込めばいいのか。
CodePipelineに新たなデプロイアクションを追加し、そこで実行するCodeBuildにてReactアプリケーションをビルドしてあげればなんとかなりそうです。最終的にビルドした生成物をS3にアップロードできさえすればあとは前回の仕組みによってデプロイが完了しますね。

CodeBuildとは?

AWSの提供するフルマネージドなビルドサービスです。動作環境にDockerイメージを用いることでどんなアプリケーションでもビルドすることが可能です。

https://aws.amazon.com/jp/codebuild/

ローカルでCodeBuildを試す

実運用中の環境でいきなり CodeBuildのリソースを作成するのは気がひけます。
なので、ローカル環境でCodeBuildが動くようにして、その中でビルド内容を定義した buildspec.yml の中身を作り込んでいこうと思います。
以下のドキュメントを参考にCodeBuildローカルの実行環境を整えます。

AWS CodeBuild エージェントを使用してビルドをローカルで実行

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

Reactアプリをビルドしたいので、ドキュメントに記載されているイメージではなくNode.jsのイメージで行いました。

https://gallery.ecr.aws/docker/library/node

ビルドに使用するイメージを変えた以外は基本的にドキュメントに記載されている通りの操作です。

# ビルドに使用するコンテナイメージをpull
docker pull public.ecr.aws/docker/library/node:16.16.0-alpine3.16

# CodeBuildエージェントをpull
docker pull public.ecr.aws/codebuild/local-builds:latest

# 実行用スクリプトのダウンロード
wget https://raw.githubusercontent.com/aws/aws-codebuild-docker-images/master/local_builds/codebuild_build.sh
chmod +x codebuild_build.sh

さて、では buildspec.yml を用意します。

buildspec.ymlとはCodeBuildで行うビルド内容を定義したファイルですね。最終的に以下のようになりましたが、

Version: 0.2
phases:
 install:
   runtime-versions:
     nodejs: 16
   commands:
     - apk update && apk upgrade
 pre_build:
   commands:
     - npm install
 build:
   commands:
     - npm run build
artifacts:
  base-directory: build
  paths: 
    - '**/*'
cache:
  paths:
    - './node_modules/**/*'

初めて実行するときは以下のように文字列を表示するだけにしてみると良さそうです。

Version: 0.2
phases:
 build:
   commands:
     - echo "Hello CodeBuild"

実行コマンドは以下のようになります。

$ ./codebuild_build.sh -i public.ecr.aws/docker/library/node:16.16.0-alpine3.16 -a artifacts

実行結果はこのように。

(ビルド時に出力されるWarningは放置していますとりあえず、、)

$ ./codebuild_build.sh -i public.ecr.aws/docker/library/node:16.16.0-alpine3.16 -a artifacts
Build Command:

docker run -it -v /var/run/docker.sock:/var/run/docker.sock -e "IMAGE_NAME=public.ecr.aws/docker/library/node:16.16.0-alpine3.16" -e "ARTIFACTS=/Users/ogiyuto/Work/reactjs/cloudscape-sandbox/artifacts" -e "SOURCE=/Users/ogiyuto/Work/reactjs/cloudscape-sandbox" -e "INITIATOR=ogiyuto" public.ecr.aws/codebuild/local-builds:latest

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] 2022/08/17 05:19:18 Waiting for agent ping
agent_1  | [Container] 2022/08/17 05:19:20 Waiting for DOWNLOAD_SOURCE
agent_1  | [Container] 2022/08/17 05:22:01 Phase is DOWNLOAD_SOURCE
agent_1  | [Container] 2022/08/17 05:22:01 CODEBUILD_SRC_DIR=/codebuild/output/src828330173/src
agent_1  | [Container] 2022/08/17 05:22:01 YAML location is /codebuild/output/srcDownload/src/buildspec.yml
agent_1  | [Container] 2022/08/17 05:22:01 Processing environment variables
agent_1  | [Container] 2022/08/17 05:22:01 [WARN] Skipping install of runtimes. Runtime version selection is not supported by this build image.
agent_1  | [Container] 2022/08/17 05:22:01 Moving to directory /codebuild/output/src828330173/src
agent_1  | [Container] 2022/08/17 05:22:01 Expanded cache path ./node_modules/**/*
agent_1  | [Container] 2022/08/17 05:22:01 Registering with agent
agent_1  | [Container] 2022/08/17 05:22:01 Phases found in YAML: 3
agent_1  | [Container] 2022/08/17 05:22:01  INSTALL: 2 commands
agent_1  | [Container] 2022/08/17 05:22:01  PRE_BUILD: 1 commands
agent_1  | [Container] 2022/08/17 05:22:01  BUILD: 1 commands
agent_1  | [Container] 2022/08/17 05:22:01 Phase complete: DOWNLOAD_SOURCE State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:01 Phase context status code:  Message:
agent_1  | [Container] 2022/08/17 05:22:01 Entering phase INSTALL
agent_1  | [Container] 2022/08/17 05:22:01 Running command apk update && apk upgrade
agent_1  | fetch https://dl-cdn.alpinelinux.org/alpine/v3.16/main/x86_64/APKINDEX.tar.gz
agent_1  | fetch https://dl-cdn.alpinelinux.org/alpine/v3.16/community/x86_64/APKINDEX.tar.gz
agent_1  | v3.16.2-31-gfe918834c6 [https://dl-cdn.alpinelinux.org/alpine/v3.16/main]
agent_1  | v3.16.2-35-g8b5106c6a8 [https://dl-cdn.alpinelinux.org/alpine/v3.16/community]
agent_1  | OK: 17024 distinct packages available
agent_1  | OK: 8 MiB in 16 packages
agent_1  |
agent_1  | [Container] 2022/08/17 05:22:03 Running command apk add aws-cli zip
agent_1  | (1/27) Installing libbz2 (1.0.8-r1)
agent_1  | (2/27) Installing expat (2.4.8-r0)
agent_1  | (3/27) Installing libffi (3.4.2-r1)
agent_1  | (4/27) Installing gdbm (1.23-r0)
agent_1  | (5/27) Installing xz-libs (5.2.5-r1)
agent_1  | (6/27) Installing mpdecimal (2.5.1-r1)
agent_1  | (7/27) Installing ncurses-terminfo-base (6.3_p20220521-r0)
agent_1  | (8/27) Installing ncurses-libs (6.3_p20220521-r0)
agent_1  | (9/27) Installing readline (8.1.2-r0)
agent_1  | (10/27) Installing sqlite-libs (3.38.5-r0)
agent_1  | (11/27) Installing python3 (3.10.5-r0)
agent_1  | (12/27) Installing groff (1.22.4-r1)
agent_1  | (13/27) Installing py3-six (1.16.0-r1)
agent_1  | (14/27) Installing py3-dateutil (2.8.2-r1)
agent_1  | (15/27) Installing py3-docutils (0.16-r4)
agent_1  | (16/27) Installing py3-jmespath (0.10.0-r2)
agent_1  | (17/27) Installing py3-urllib3 (1.26.9-r0)
agent_1  | (18/27) Installing py3-botocore (1.21.49-r1)
agent_1  | (19/27) Installing py3-s3transfer (0.5.1-r0)
agent_1  | (20/27) Installing py3-colorama (0.4.4-r2)
agent_1  | (21/27) Installing yaml (0.2.5-r0)
agent_1  | (22/27) Installing py3-yaml (6.0-r0)
agent_1  | (23/27) Installing py3-asn1 (0.4.8-r2)
agent_1  | (24/27) Installing py3-rsa (4.8-r0)
agent_1  | (25/27) Installing aws-cli (1.22.81-r0)
agent_1  | (26/27) Installing unzip (6.0-r9)
agent_1  | (27/27) Installing zip (3.0-r9)
agent_1  | Executing busybox-1.35.0-r17.trigger
agent_1  | OK: 141 MiB in 43 packages
agent_1  |
agent_1  | [Container] 2022/08/17 05:22:18 Phase complete: INSTALL State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:18 Phase context status code:  Message:
agent_1  | [Container] 2022/08/17 05:22:18 Entering phase PRE_BUILD
agent_1  | [Container] 2022/08/17 05:22:18 Running command npm install
agent_1  | npm WARN ERESOLVE overriding peer dependency
agent_1  | npm WARN While resolving: react-resizable@1.11.1
agent_1  | npm WARN Found: react@18.2.0
agent_1  | npm WARN node_modules/react
agent_1  | npm WARN   react@"^18.2.0" from the root project
agent_1  | npm WARN   12 more (@cloudscape-design/collection-hooks, ...)
agent_1  | npm WARN
agent_1  | npm WARN Could not resolve dependency:
agent_1  | npm WARN peer react@"0.14.x || 15.x || 16.x || 17.x" from react-resizable@1.11.1
agent_1  | npm WARN node_modules/@cloudscape-design/components/node_modules/react-resizable
agent_1  | npm WARN   react-resizable@"^1.11.1" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN   node_modules/@cloudscape-design/components
agent_1  | npm WARN
agent_1  | npm WARN Conflicting peer dependency: react@17.0.2
agent_1  | npm WARN node_modules/react
agent_1  | npm WARN   peer react@"0.14.x || 15.x || 16.x || 17.x" from react-resizable@1.11.1
agent_1  | npm WARN   node_modules/@cloudscape-design/components/node_modules/react-resizable
agent_1  | npm WARN     react-resizable@"^1.11.1" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN     node_modules/@cloudscape-design/components
agent_1  | npm WARN ERESOLVE overriding peer dependency
agent_1  | npm WARN While resolving: react-resizable@1.11.1
agent_1  | npm WARN Found: react-dom@18.2.0
agent_1  | npm WARN node_modules/react-dom
agent_1  | npm WARN   react-dom@"^18.2.0" from the root project
agent_1  | npm WARN   4 more (@cloudscape-design/components, ...)
agent_1  | npm WARN
agent_1  | npm WARN Could not resolve dependency:
agent_1  | npm WARN peer react-dom@"0.14.x || 15.x || 16.x || 17.x" from react-resizable@1.11.1
agent_1  | npm WARN node_modules/@cloudscape-design/components/node_modules/react-resizable
agent_1  | npm WARN   react-resizable@"^1.11.1" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN   node_modules/@cloudscape-design/components
agent_1  | npm WARN
agent_1  | npm WARN Conflicting peer dependency: react-dom@17.0.2
agent_1  | npm WARN node_modules/react-dom
agent_1  | npm WARN   peer react-dom@"0.14.x || 15.x || 16.x || 17.x" from react-resizable@1.11.1
agent_1  | npm WARN   node_modules/@cloudscape-design/components/node_modules/react-resizable
agent_1  | npm WARN     react-resizable@"^1.11.1" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN     node_modules/@cloudscape-design/components
agent_1  | npm WARN ERESOLVE overriding peer dependency
agent_1  | npm WARN While resolving: react-virtual@2.10.4
agent_1  | npm WARN Found: react@18.2.0
agent_1  | npm WARN node_modules/react
agent_1  | npm WARN   react@"^18.2.0" from the root project
agent_1  | npm WARN   12 more (@cloudscape-design/collection-hooks, ...)
agent_1  | npm WARN
agent_1  | npm WARN Could not resolve dependency:
agent_1  | npm WARN peer react@"^16.6.3 || ^17.0.0" from react-virtual@2.10.4
agent_1  | npm WARN node_modules/@cloudscape-design/components/node_modules/react-virtual
agent_1  | npm WARN   react-virtual@"^2.8.2" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN   node_modules/@cloudscape-design/components
agent_1  | npm WARN
agent_1  | npm WARN Conflicting peer dependency: react@17.0.2
agent_1  | npm WARN node_modules/react
agent_1  | npm WARN   peer react@"^16.6.3 || ^17.0.0" from react-virtual@2.10.4
agent_1  | npm WARN   node_modules/@cloudscape-design/components/node_modules/react-virtual
agent_1  | npm WARN     react-virtual@"^2.8.2" from @cloudscape-design/components@3.0.10
agent_1  | npm WARN     node_modules/@cloudscape-design/components
agent_1  |
agent_1  | up to date, audited 1482 packages in 9s
agent_1  |
agent_1  | 205 packages are looking for funding
agent_1  |   run `npm fund` for details
agent_1  |
agent_1  | 6 high severity vulnerabilities
agent_1  |
agent_1  | To address all issues (including breaking changes), run:
agent_1  |   npm audit fix --force
agent_1  |
agent_1  | Run `npm audit` for details.
agent_1  |
agent_1  | [Container] 2022/08/17 05:22:28 Phase complete: PRE_BUILD State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:28 Phase context status code:  Message:
agent_1  | [Container] 2022/08/17 05:22:28 Entering phase BUILD
agent_1  | [Container] 2022/08/17 05:22:28 Running command npm run build
agent_1  |
agent_1  | > cloudscape-sandbox@0.1.0 build
agent_1  | > react-scripts build
agent_1  |
agent_1  | Creating an optimized production build...
agent_1  | Compiled with warnings.
agent_1  |
agent_1  | [eslint]
agent_1  | src/App.js
agent_1  |   Line 9:8:  'Editor' is defined but never used  no-unused-vars
agent_1  |
agent_1  | src/components/Cards.js
agent_1  |   Line 10:1:  Assign arrow function to a variable before exporting as module default  import/no-anonymous-default-export
agent_1  |
agent_1  | src/components/Editor.js
agent_1  |   Line 4:1:   Assign arrow function to a variable before exporting as module default  import/no-anonymous-default-export
agent_1  |   Line 8:19:  'setLoading' is assigned a value but never used                         no-unused-vars
agent_1  |
agent_1  | src/components/Table.js
agent_1  |   Line 10:1:  Assign arrow function to a variable before exporting as module default  import/no-anonymous-default-export
agent_1  |
agent_1  | Search for the keywords to learn more about each warning.
agent_1  | To ignore, add // eslint-disable-next-line to the line before.
agent_1  |
agent_1  | File sizes after gzip:
agent_1  |
agent_1  |   82.62 kB  build/static/js/main.1a6fd71a.js
agent_1  |   31.86 kB  build/static/css/main.d2a0b07d.css
agent_1  |
agent_1  | The project was built assuming it is hosted at /.
agent_1  | You can control this with the homepage field in your package.json.
agent_1  |
agent_1  | The build folder is ready to be deployed.
agent_1  | You may serve it with a static server:
agent_1  |
agent_1  |   npm install -g serve
agent_1  |   serve -s build
agent_1  |
agent_1  | Find out more about deployment here:
agent_1  |
agent_1  |   https://cra.link/deployment
agent_1  |
agent_1  |
agent_1  | [Container] 2022/08/17 05:22:57 Phase complete: BUILD State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:57 Phase context status code:  Message:
agent_1  | [Container] 2022/08/17 05:22:57 Entering phase POST_BUILD
agent_1  | [Container] 2022/08/17 05:22:57 Phase complete: POST_BUILD State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:57 Phase context status code:  Message:
agent_1  | [Container] 2022/08/17 05:22:57 Expanding base directory path: build
agent_1  | [Container] 2022/08/17 05:22:57 Assembling file list
agent_1  | [Container] 2022/08/17 05:22:57 Expanding build
agent_1  | [Container] 2022/08/17 05:22:57 Expanding file paths for base directory build
agent_1  | [Container] 2022/08/17 05:22:57 Assembling file list
agent_1  | [Container] 2022/08/17 05:22:57 Expanding **/*
agent_1  | [Container] 2022/08/17 05:22:57 Found 12 file(s)
agent_1  | [Container] 2022/08/17 05:22:57 Preparing to copy secondary artifacts
agent_1  | [Container] 2022/08/17 05:22:57 No secondary artifacts defined in buildspec
agent_1  | [Container] 2022/08/17 05:22:57 Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED
agent_1  | [Container] 2022/08/17 05:22:57 Phase context status code:  Message:
agent-resources_build_1 exited with code 0
Aborting on container exit...

じっさいのCodeBuildでは ビルドによる生成物(artifact)はS3へアップロードされますが、

ローカルの場合は codebuild_build.sh の引数で指定した場所に生成されます。

$ tree artifacts
artifacts
└── artifacts.zip

0 directories, 1 file

artifacts.zipを解凍してみると、このように。

$ tree artifacts/artifacts

artifacts/artifacts
├── asset-manifest.json
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── static
    ├── css
    │   ├── main.d2a0b07d.css
    │   └── main.d2a0b07d.css.map
    └── js
        ├── main.1a6fd71a.js
        ├── main.1a6fd71a.js.LICENSE.txt
        └── main.1a6fd71a.js.map

3 directories, 12 files

npm run build で生成されたファイルが含まれていることが確認できました。

困ったこと

ここまで順調に進んでいるように見えますが、私の環境では codebuild_build.sh の処理が完了するまで、M1Macで40分、IntelMacで3分ほどかかっています。
(ARM用のCodeBuildイメージが提供されているのですが、それを使っても同じ実行時間でした)

ということで 今回の検証は プライベート開発用の IntelMacで行いました。幸い今回の検証ではReactのビルドしかしていませんが、CodeBuildでもっと複雑な処理をしたい場合はこの3分間はちょっと辛そうです。

終わりに

あとは実際に CodeBuildのリソースを作成して実地確認ですかねー。
CodeBuild artifactはS3にアップロードされるので、それをフックに 前回調査 したAmplifyのマニュアルビルドを起動してあげれば、CodePipelineからのAmplifyデプロイが構築できそうです。

楽しみですね!


静岡県浜松市のアプリケーションデベロッパー。ITコミュニティやシビックテックにも興味があります。