CodeBuildでjavaのソースコードをビルドする

# はじめに
CodeBuildを使ってjavaのソースコードをビルドします。

# 構成
![スクリーンショット 2021-05-07 16.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/7660b6e8-f6a4-530a-52b3-b8fecdbb58fc.png)


# 作業
基本的にはコンソール操作ですがソースの準備部分でコマンドも記載しています。コマンドを使わなくても同じ状況になれば大丈夫です。

## S3バケットの作成
まず、バケットを2つ用意します。

- **ソースコード用：**codebuild-[regionID]-[accountID]-input-bucket
- **ビルド出力用：**codebuild-[regionID]-[accountID]-output-bucket

S3バケット名はユニークでないといけないため**[regionID]**と**[accountID]**というルールを設けています。

## ソースコードの準備
CodeBuildでビルドするためのソースコードを作成します。
空のディレクトリを用意し、その配下に以下のようなディレクトリ構造を作成します。

```bash:ディレクトリ作成
$ mkdir work
$ cd work
$ mkdir -p src/main/java
$ mkdir -p src/test/java
```

```text:ディレクトリ構造
(root directory name)
    `-- src
         |-- main
         |     `-- java
         `-- test
               `-- java
```
また、`src/main/java`配下に`MessageUtil.java`というファイルを作成します。

```bash:javaファイル作成
$ vim ./src/main/java/MessageUtil.java
```

```java:MessageUtil.java
public class MessageUtil {
  private String message;

  public MessageUtil(String message) {
    this.message = message;
  }

  public String printMessage() {
    System.out.println(message);
    return message;
  }

  public String salutationMessage() {
    message = "Hi!" + message;
    System.out.println(message);
    return message;
  }
}
```
次に、`src/test/java`配下に`TestMessageUtil.java`というファイルを作成します。

```bash:javaファイル作成
$ vim ./src/test/java/TestMessageUtil.java
```

```java:TestMessageUtil.java
import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class TestMessageUtil {

  String message = "Robert";    
  MessageUtil messageUtil = new MessageUtil(message);
   
  @Test
  public void testPrintMessage() {      
    System.out.println("Inside testPrintMessage()");     
    assertEquals(message,messageUtil.printMessage());
  }

  @Test
  public void testSalutationMessage() {
    System.out.println("Inside testSalutationMessage()");
    message = "Hi!" + "Robert";
    assertEquals(message,messageUtil.salutationMessage());
  }
}
```
次に、作業ルートディレクトリに`pom.xml`というファイルを作成します。

```bash:xmlファイル作成
$ vim pom.xml
```

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>messageUtil</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>
  <name>Message Utility Java Sample App</name>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>	
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
      </plugin>
    </plugins>
  </build>
</project>
```
最終的に以下のような構造になります。

```text:ディレクトリ構造
(root directory name)
    |-- pom.xml
    `-- src
         |-- main
         |     `-- java
         |           `-- MessageUtil.java
         `-- test
               `-- java
                     `-- TestMessageUtil.java
```


## buildspecファイルの作成
buildspecはCodeBuildでどのような処理を行うかを記載したレシピになります。

```bash:buildspec作成
$ vim buildspec.yml
```

```yml:buildspec.yml
version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto11
  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
  build:
    commands:
      - echo Build started on `date`
      - mvn install
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - target/messageUtil-1.0.jar
```
ここまでの構造は以下になります。

```text:ディレクトリ構造
(root directory name)
    |-- pom.xml
    |-- buildspec.yml
    `-- src
         |-- main
         |     `-- java
         |           `-- MessageUtil.java
         `-- test
               `-- java
                     `-- TestMessageUtil.java
```

## ソースコードと buildspec ファイルのアップロード
ここまでで用意したものをzipファイルにします。

```bash:
$ zip -r MessageUtil.java *
```
zipファイル内の構造は以下になっている必要があります。

```text:MessageUtil.zip
MessageUtil.zip
    |-- pom.xml
    |-- buildspec.yml
    `-- src
         |-- main
         |     `-- java
         |           `-- MessageUtil.java
         `-- test
               `-- java
                     `-- TestMessageUtil.java
```
zipファイルにしたら最初に作成したinputバケット(`codebuild-[regionID]-[accountID]-input-bucket`)へアップロードします。
![スクリーンショット 2021-05-04 17.41.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/e3059a78-480a-2dd2-c7e5-48fb5ed59e18.png)

## ビルドプロジェクトの作成
CodeBuildでビルドを実行するためのビルドプロジェクトを作成します。

まず、**[ビルドプロジェクト] → [ビルドプロジェクトを作成する]**をクリックします。
![スクリーンショット 2021-05-04 17.29.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/51f21654-0f20-a9b8-4465-3800320c09ff.png)

**・プロジェクトの設定**
次に、**プロジェクトの設定**の**プロジェクト名**にビルドプロジェクトの名前(ここでは`codebuild-demo-project`)を入力します。

|項目 |値 |
|--- |---|
| プロジェクト名  | codebuild-demo-project |

**・ソース**
**ソースプロバイダ**で**AmazonS3**を選択し、**バケット**に`codebuild-[regionID]-[accountID]-input-bucket`を選択、**S3オブジェクトキーまたはS3フォルダ**に`MessageUtil.zip`を入力します。

|項目 |値 |
|--- |---|
| ソースプロバイダ | Amazon S3 |
| バケット       | codebuild-[regionID]-[accountID]-input-bucket |
| S3オブジェクトキーまたはS3フォルダ | MessageUtil.zip |


**・環境**
**環境イメージ**で**マネージド型イメージ**を選択し、**オペレーティングシステム**で**AmazonLinux2**を選択、**ランタイム**に**Standard**、**イメージ**に**aws/codebuild/amazonlinux2-x86_64-standard:3.0**を選択します。
**サービスロール**では**新しいサービスロール**を選択したままで、**ロール名**もそのままにします。

|項目 |値 |
|--- |---|
| 環境イメージ | マネージド型イメージ |
| オペレーティングシステム | AmazonLinux2 |
| ランタイム | Standard |
| イメージ | aws/codebuild/amazonlinux2-x86_64-standard:3.0 |
| ランタイム | Standard |
| サービスロール | 新しいサービスロール |
| ロール名 | 自動入力されたもの |

**・Buildspec**
**buildspecファイルを使用する**を選択したままにします。

|項目 |値 |
|--- |---|
| buildspec | buildspecファイルを使用する |

**・アーティファクト**
**タイプ**を**Amazon S3**にし、**バケット名**に`codebuild-[regionID]-[accountID]-output-bucket`を選択します。

|項目 |値 |
|--- |---|
| タイプ | Amazon S3 |
| バケット名 | codebuild-[regionID]-[accountID]-output-bucket |

以下は実際の入力例です。
![screencapture-ap-northeast-1-console-aws-amazon-codesuite-codebuild-project-new-2021-05-04-17_39_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/fa1959a2-1892-57f0-0037-a768ca1df727.png)

入力が完了したら**[ビルドプロジェクトの作成]**をクリックします。


## ビルドの実行
先ほど用意したビルドプロジェクトでビルドを実行します。
**[ビルドプロジェクト] → [ビルドの開始]**をクリックします。
![スクリーンショット 2021-05-04 17.40.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/20d21fd3-0816-437e-9822-399388d7f0f5.png)

## 確認
ビルドが完了すると、出力先に指定した`codebuild-[regionID]-[accountID]-output-bucket`にjarファイルが出力されます。
![スクリーンショット 2021-05-04 18.08.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/e3e7b935-208d-aa64-9959-5b8e373fe08c.png)


# おわりに
CodeBuildを利用することで今まで必要だったビルドサーバーのサーバーレス化が行えます。
サーバー費用の削減だけでなく、運用コストも大幅に削減できるのでとても助かるサービスだなと感じました。