4
0

More than 1 year has passed since last update.

M2 MacでCodeBuildをローカルで実行する。

Posted at

はじめに

勉強のため、AWSCodeBuildを使ってみようと思ってドキュメントを見ていたところ、いちいちマネジメントコンソール画面からCodeBuildを実行しなくてもローカルマシンにビルド環境を構築することができるとのことなので、M2 Macのマシンでローカルビルド環境を構築してみました。

CodeBuildとは

アプリケーションを開発して動作させるようにするには、ソースコードをコンパイルしたり、必要なファイル等をまとめて資材を作成したりする必要がありますが、そのような面倒な作業をAWS側のサービスとして提供して、開発者の手間を減らしたり、CodeDeployCodePipeline等の他サービスと連携することでアプリケーションのリリース作業を自動化したりするためのサービスです。

実際にどのファイルをどのようなコマンドオプションでコンパイルする等のCodeBuildで行う作業はbuildspec.ymlというファイルに記述して、その内容をCodeBuildで実行することで、指定のビルドが行えるようになっております。

CodeBuildをローカルで実行するということ

上述の通り、CodeBuildAWSのマネージドサービスとなるため、buildspec.ymlで記述した設定が正しいかを確かめるためには通常AWSのマネジメントコンソール画面やAWS CLIから実際に実行してみるしかありませんが、作成中のbuildspec.ymlをいちいちCodeBuildの画面から実行してデバッグしていくのは一苦労ということで、ローカルマシン上でも環境を用意すればCodeBuildを実行できるようにしているそうです。

ローカルマシンで実行する場合とAWS上でCodeBuildを実行する場合の違い

CodeBuildはビルドプロジェクトと言うビルドの設計図を実行する際、Dockerコンテナを起動して、buildspec.ymlの内容を実行する仕組みとなっています。

ローカルで実行する場合もCodeBuildで実際に使用しているコンテナイメージを使用してローカルでbuildspec.ymlの内容を実行する仕組みとなるため、Dockerコンテナをどこで実行しているかという違いはありますが、環境の違い以外は同等のことが行えるようです。

ちなみに、CodeBuildはアプリケーションのビルドを実行することを目的としておりますが、そもそもがDockerコンテナなのでbuildspec.ymlの書き方次第でビルドとは関係ない処理も実行することができるそうなので、知っておくと設計の幅を広げることもできるかもしれません。

CodeBuildをローカルで実行する準備

導入方法は以下のAWS公式ドキュメントに記載されているため、こちらに沿って実行していきます。

M2MacBook AirにAWS公式イメージを導入する場合の流れは以下となります。

 - Gitクライアントインストール
 - Dockerインストール
 - Amazon Linux 2 のDockerイメージのダウンロード
 - エージェントのDockerイメージのダウンロード
 - CodeBuildエージェントのダウンロード
 - buildspec.ymlの作成
 - CodeBuildエージェントの実行
 

Gitクライアント、Dockerインストール

こちらは今回は紹介しませんが、それぞれダウンロードしてインストールしておきます。

Amazon Linux 2 のDockerイメージダウンロード

公式ドキュメント通り、docker pullコマンドでDockerイメージをダウンロードします。
バージョンについてはドキュメントのバージョンより新しいバージョンが出ているようなので、以下のように指定します。

Dockerイメージダウンロード
docker pull public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:4.0

エージェントのDockerイメージダウンロード

上記と同様docker pullコマンドでダウンロードします。

今回は実行マシンとしてM2 Macを使用するので、ARM版をダウンロードします。

エージェント用Dockerイメージダウンロード
docker pull public.ecr.aws/codebuild/local-builds:aarch64

CodeBuildエージェントのダウンロード

以下のように実行してエージェントをダウンロードします。

公式ドキュメントはwgetでダウンロードしておりますが、M2 Macにはデフォルトでwgetが含まれていないため、curlコマンドを以下のようにしてダウンロードします。

CodeBuildエージェントのダウンロード
curl -OL 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エージェントのシェルと同じ場所に格納しておきます。

定番のHello Worldを表示するビルド定義ファイルです。

buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - echo 'Hello World'

CodeBuildエージェントの実行

最低限以下のようにして実行することでローカルで実行できます。

-aで指定するアーティファクト(生成物)は特に生成するような設定をしていなくても指定する必要があるので、適当な場所を指定しておきます。

CloudBuildエージェントの実行
./codebuild_build.sh -i public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:4.0 -a artifact_output -l public.ecr.aws/codebuild/local-builds:aarch64

以下の結果のようにHello Worldの表示が出力され、exitコードが0になっていればOKです。

実行結果の抜粋
(省略)
agent_1  | [Container] 2022/09/01 12:54:01 Running command echo 'Hello World'
agent_1  | Hello World
agent_1  |
(省略)
agent-resources_agent_1 exited with code 0
Stopping agent-resources_build_1 ... done
Aborting on container exit...

codebuild_build.shのオプション

codebuild_build.shをオプション無しで実行した際のUSAGEでも内容が確認できますが、以下のオプションが指定可能です。

下記の書式の通り、-i-aが必須オプションとなります。

codebuild_build.shの書式
codebuild_build.sh [-i image_name] [-a artifact_output_directory] [options]
オプション 説明
-i [イメージ名] 使用するコンテナイメージの指定(必須)
-a [出力先] アーティファクト(生成物)の出力先の指定(必須)
-l [イメージ名] デフォルトのローカルエージェントイメージを上書き
-r [出力先] レポートの出力先の指定
-s [ディレクトリパス] ソースディレクトリの場所の指定
2つ目以降は、<sourceIdentifier>:<sourceLocation>の書式で指定
-c ローカルのAWS認証情報を使用する場合に指定
-p [プロファイル名] デフォルト以外のプロファイルを使用する場合に指定
指定する場合は-cと一緒に使用
-b [ファイルパス] buildspec.ymlの名前以外でファイル名を使用する場合に指定
指定する場合、カレントディレクトリからの相対パスか絶対パスで指定
-m ソースディレクトリをコンテナに直接マウントする場合に指定
-d 特権モードでDockerコンテナを実行する場合に指定
-e [環境変数ファイルパス] 環境変数を記載したファイルを使用する場合に指定

それぞれCodeBuildのマネジメントコンソール画面の設定値に当てはまる内容となり、現状は上記のオプションが全てとなります。

以下でいくつかのオプションについて補足します。

-l デフォルトローカルエージェントイメージ上書き

特にオプションを指定しない場合、デフォルトのpublic.ecr.aws/codebuild/local-builds:latestが指定されますが、デフォルト以外のローカルエージェントイメージを使用したい場合に指定します。

例えばARM用のローカルエージェントイメージとなるpublic.ecr.aws/codebuild/local-builds:aarch64を使用したい場合は-lが必要となります。

-r テストレポートの出力先の指定

JUnitJaCoCoといったテストフレームワークを使ったテストをbuildspec.ymlに盛り込んでいる場合、テストレポートを指定の場所に出力できるとのこと。

テストフレームワークについて私は詳しくないので、気になる方は以下のようなサイトをご確認ください。

-s ソースディレクトリの場所の指定

マネジメントコンソール上の設定で言うと、ソースの設定に当たります。

ローカルで実行する場合、CodeCommitS3をソースに指定できないため、指定するディレクトリはローカルのパスとなり、何も指定しなかった場合はカレントディレクトリがソースディレクトリとなります。

また、1つ目のソースディレクトリにbuildspec.ymlの名前でビルド定義ファイルを格納している場合は、自動で認識するため、-bオプションは不要となります。

逆に1つ目のソースディレクトリ内にbuildspec.ymlが存在しなかったり、別のファイル名にしている場合は-bオプションで指定する必要があります。

2つ以上のソースディレクトリを指定する場合は、ディレクトリパス以外に<sourceIdentifier>という識別子の指定が必要となります。

これは、ソースディレクトリを呼び出す際、内部的に以下のような予約環境変数を使用しているため、識別子がないと識別できないからとなります。

変数 説明
CODEBUILD_SRC_DIR 1つ目のソースディレクトリパスを格納している変数
CODEBUILD_SRC_DIR_[識別子] 1つ目以降のソースディレクトリパスを格納している変数

予約されている変数は以下を参照してください。

-c、-p AWS認証情報の使用

-cbuildspec.yml内でAWS CLIを使用したい場合にローカルマシンに設定しているAWS認証情報(~/.aws配下の情報)を使いたい場合に指定するオプションです。

また、-pdefaultプロファイル以外のプロファイルを使用したい場合に指定するオプションです。

-m ソースディレクトリをコンテナに直接マウント

ローカルでCodeBuildを実行する場合、通常はDockerコンテナ起動時にソースディレクトリのファイルをコンテナ内にコピーしてから処理が実行されるそうですが、-mを使用すると、ソースディレクトリのファイルをコピーするのではなく、ソースディレクトリを直接マウントする動作となるようです。

試しにソースディレクトリ配下に1GBのファイルを作成し、起動してみたところ、-mをつけない場合はソースディレクトリ配下のファイルダウンロードに20秒かかっているのに対し、-mをつけてDockerコンテナに直接マウントさせたところ、1秒ですみました。

-mをつけない場合のダウンロード時間
(抜粋)
agent_1  | [Container] 2022/09/02 11:58:20 Waiting for agent ping
agent_1  | [Container] 2022/09/02 11:58:21 Waiting for DOWNLOAD_SOURCE
agent_1  | [Container] 2022/09/02 11:58:41 Phase is DOWNLOAD_SOURCE
-mをつけた場合のダウンロード時間
(抜粋)
agent_1  | [Container] 2022/09/02 11:59:01 Waiting for agent ping
agent_1  | [Container] 2022/09/02 11:59:02 Waiting for DOWNLOAD_SOURCE
agent_1  | [Container] 2022/09/02 11:59:03 Phase is DOWNLOAD_SOURCE

実際のCodeCommitのマネジメントコンソール画面上にはそのような項目は見当たらなかったので、ローカル実行する場合だけの設定なのかな?

-e 環境変数の指定

CodeBuildで環境変数を設定したい場合、buildspec.ymlenvシーケンスに直接記載するか、マネジメントコンソールからCodeBuildの定義を行う際に設定するなどの方法で設定できますが、ローカル実行する場合、マネジメントコンソールから環境変数を設定する代わりに、環境変数を記載したファイルを作成して、そのファイルをCodeBuild実行時に読み込ませることでビルド定義ファイル内で変数として使用できます。

変数の書き方は一般的なシェルの環境変数の指定方法で記載すればOKです。

codebuild_build.shで作られるDockerコンテナ削除

codebuild_build.shの仕様というよりDockerの仕様ですが、codebuild_build.shCodeBuildをローカル実行するとローカルビルド時に使用した終了済みのコンテナが残ってしまいリソースを圧迫してしまいます。(以下の場合NAMESagent-resources_build_1agent-resources_agent_1以外のコンテナが実行後の不要コンテナ)

何度かローカル実行した後のdocker_ps_-a結果
CONTAINER ID   IMAGE                                                       COMMAND                  CREATED         STATUS                       PORTS                    NAMES
50d3da581ad7   public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:4.0   "sh -c 'while [ ! -f…"   3 minutes ago   Exited (137) 3 minutes ago                            agent-resources_build_1
c9968c8c4740   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         3 minutes ago   Exited (0) 3 minutes ago                              agent-resources_agent_1
fe6fb6edb995   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         3 minutes ago   Exited (0) 3 minutes ago                              stoic_cartwright
1f3947824af4   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         3 minutes ago   Exited (0) 3 minutes ago                              sad_wilbur
5a2aefe94637   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         4 minutes ago   Exited (0) 3 minutes ago                              jovial_lichterman
4f95a2ce88f4   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         4 minutes ago   Exited (0) 4 minutes ago                              infallible_hellman
795095d32638   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         4 minutes ago   Exited (0) 4 minutes ago                              sleepy_cori
6d6acece1148   public.ecr.aws/codebuild/local-builds:aarch64               "local_build.sh"         4 minutes ago   Exited (0) 4 minutes ago                              intelligent_williamson

そもそもcodebuild_build.shを使う目的としてCodeBuildの動作を確認するためであり、再利用する必要も無いことからcodebuild_build.shの中身を以下のように少し編集して、実行完了後に不要となるコンテナが削除されるようにしたほうが良いでしょう。

codebuild_build.sh実行終了後に不要コンテナを削除するオプション(99行目付近)
docker_command="docker run -it "
↓↓以下に変更↓↓
docker_command="docker run --rm -it "

(おまけ)オプションもりもりの実行

オプション動作が分かりづらいものもあるため、実行例かねてオプションもりもりで実行してみようと思います。

以下のような想定で実施します。

設定 説明
アーティファクトディレクトリ codebuild/artifact
1つ目のソースディレクトリ codebuild/sourcedir1
2つ目のソースディレクトリ codebuild/sourcedir2
識別子 IDENTIFIER
AWS認証情報プロファイル codebuild
ソースディレクトリマウント する
ビルド定義ファイル名 codebuild.yml
環境変数ファイル名 variable.env
variable.env
VAR="variable_test"
codebuild.yml
version: 0.2

phases:
  install:
    commands:
      - echo ${VAR}
      - ls -l ${CODEBUILD_SRC_DIR}/
      - ls -l ${CODEBUILD_SRC_DIR_IDENTIFIER}/
      - aws s3 ls
artifacts:
  files:
    - '**/*'
  name: codebuild/artifact
実行マシン側ディレクトリ構成
~/
├── codebuild/
│      ├── artifact/
│      ├── sourcedir1/
│   │   ├── codebuild.yml
│   │   └── testfile1
│      └── sourcedir2/
│       └── testfile2
├── codebuild_build.sh
└── variable.env

ビルド定義ファイルはDockerでの動作を確認するため、以下のコマンドを実行します。

コマンド 用途
echo ${VAR} 環境変数呼び出し確認
ls -l ${CODEBUILD_SRC_DIR}/ 1つ目のソースディレクトリ変数が呼び出せるかの確認
ls -l ${CODEBUILD_SRC_DIR_IDENTIFIER}/ 2つ目のソースディレクトリ変数が呼び出せるかの確認
aws s3 ls aws-cliでAWS環境にアクセスできるかの確認

2つ目のソースディレクトリを指定している変数は実行時に指定する識別子によって変わるので環境によって変更してください。

また、aws-cliは、実行マシン側のIAMユーザ情報を使ってアクセスするため、もしアクセスできなかった場合は権限周りを確認しましょう。

オプションもりもりのコマンド例
./codebuild_build.sh -c -m \
-i public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:4.0 \
-a codebuild/artifact \
-l public.ecr.aws/codebuild/local-builds:aarch64 \
-e variable.env \
-p codebuild \
-s codebuild/sourcedir1 \
-s IDENTIFIER:codebuild/sourcedir2 \
-b codebuild/sourcedir1/codebuild.yml
オプションもりもりのコマンド実行例(展開してください)
オプションもりもりのコマンド実行結果
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/09/02 13:05:05 Waiting for agent ping
agent_1  | [Container] 2022/09/02 13:05:06 Waiting for DOWNLOAD_SOURCE
agent_1  | [Container] 2022/09/02 13:05:07 Phase is DOWNLOAD_SOURCE
agent_1  | [Container] 2022/09/02 13:05:07 CODEBUILD_SRC_DIR=/codebuild/output/src041/src
agent_1  | [Container] 2022/09/02 13:05:07 CODEBUILD_SRC_DIR_IDENTIFIER=/codebuild/output/src041/secSrc/IDENTIFIER
agent_1  | [Container] 2022/09/02 13:05:07 YAML location is /codebuild/output/srcDownload/src/codebuild.yml
agent_1  | [Container] 2022/09/02 13:05:07 Processing environment variables
agent_1  | [Container] 2022/09/02 13:05:08 Moving to directory /codebuild/output/src041/src
agent_1  | [Container] 2022/09/02 13:05:08 Registering with agent
agent_1  | [Container] 2022/09/02 13:05:08 Phases found in YAML: 1
agent_1  | [Container] 2022/09/02 13:05:08  INSTALL: 4 commands
agent_1  | [Container] 2022/09/02 13:05:08 Phase complete: DOWNLOAD_SOURCE State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:08 Phase context status code:  Message:
agent_1  | [Container] 2022/09/02 13:05:08 Entering phase INSTALL
agent_1  | [Container] 2022/09/02 13:05:08 Running command echo ${VAR}
agent_1  | "variable_test"
agent_1  |
agent_1  | [Container] 2022/09/02 13:05:08 Running command ls -l ${CODEBUILD_SRC_DIR}/
agent_1  | total 4
agent_1  | -rw-r--r-- 1 root root 228 Sep  2 12:59 codebuild.yml
agent_1  | -rw-r--r-- 1 root root   0 Sep  1 13:19 testfile1
agent_1  |
agent_1  | [Container] 2022/09/02 13:05:08 Running command ls -l ${CODEBUILD_SRC_DIR_IDENTIFIER}/
agent_1  | total 0
agent_1  | -rw-r--r-- 1 root root 0 Sep  1 13:19 testfile2
agent_1  |
agent_1  | [Container] 2022/09/02 13:05:08 Running command aws s3 ls
agent_1  | 2022-08-26 12:31:35 [s3バケット名]
agent_1  | 2022-07-23 04:28:16 [s3バケット名]
agent_1  | 2022-07-24 23:58:28 [s3バケット名]
agent_1  |
agent_1  | [Container] 2022/09/02 13:05:12 Phase complete: INSTALL State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:12 Phase context status code:  Message:
agent_1  | [Container] 2022/09/02 13:05:12 Entering phase PRE_BUILD
agent_1  | [Container] 2022/09/02 13:05:12 Phase complete: PRE_BUILD State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:12 Phase context status code:  Message:
agent_1  | [Container] 2022/09/02 13:05:12 Entering phase BUILD
agent_1  | [Container] 2022/09/02 13:05:12 Phase complete: BUILD State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:12 Phase context status code:  Message:
agent_1  | [Container] 2022/09/02 13:05:12 Entering phase POST_BUILD
agent_1  | [Container] 2022/09/02 13:05:12 Phase complete: POST_BUILD State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:12 Phase context status code:  Message:
agent_1  | [Container] 2022/09/02 13:05:12 Expanding base directory path: .
agent_1  | [Container] 2022/09/02 13:05:12 Assembling file list
agent_1  | [Container] 2022/09/02 13:05:12 Expanding .
agent_1  | [Container] 2022/09/02 13:05:12 Expanding file paths for base directory .
agent_1  | [Container] 2022/09/02 13:05:12 Assembling file list
agent_1  | [Container] 2022/09/02 13:05:12 Expanding **/*
agent_1  | [Container] 2022/09/02 13:05:13 Found 2 file(s)
agent_1  | [Container] 2022/09/02 13:05:13 Preparing to copy secondary artifacts
agent_1  | [Container] 2022/09/02 13:05:13 No secondary artifacts defined in buildspec
agent_1  | [Container] 2022/09/02 13:05:13 Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED
agent_1  | [Container] 2022/09/02 13:05:13 Phase context status code:  Message:
agent-resources_build_1 exited with code 0
Aborting on container exit...

S3バケット名だけ一部マスク。

コマンド実行完了後、codebuild/artifactにソースディレクトリが固められたZIPファイルも存在確認できました。

おわりに

CodeBuildをマネジメントコンソール上で実行する場合、単純な内容のビルドでも数分かかりますが、ローカルで実行した場合、いくつか制約はあるにせよ、マネジメントコンソールから実行するより早く確認できるので、buildspec.yml自体の動作チェックを行うのに最適です。

また、codebuild_build.shはオプションさえ覚えてしまえば非常に簡単にローカルでCodeBuildが試せることがわかりました。

CodeBuildはあまり触ったことがなかったのですが、実際にローカルで動かしてみて、CodeBuild自体、かなり自由度が高いサービスなのだと感じました。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0