GitHub Actionsを使って、SpringBoot + NuxtアプリケーションをElasticBeanstalkにデプロイしてみた

# はじめに
GitHub Actionsが正式に公開されたので、調査がてらSpringBootアプリケーションをElasticBeanstalkにデプロイしてみました。

# 前提

- AWS（IAM）アカウントを持っていること。
- ElasticBeanstalkに環境が構築済みであること。
- GitHubアカウントを持っていること。

# 手順

## SpringBootプロジェクト作成

プロジェクト作成時の依存関係は、「Web」のみ選択します。

ElasticBeanstalkのnginxが5000ポートでアクセスするので、SpringBootアプリケーションの起動ポートを変更します。

```properties:application.properties
server.port=5000
```

RestControllerを作成します。

```java:DemoController.java
@RestController
@RequestMapping(path = "/demo")
public class DemoController {
    @GetMapping
    public String hello() {
        return "Hello, GitHub Actions!";
    }
}
```

## Nuxtプロジェクト作成

SpringBootプロジェクトのルートで以下のコマンドを実行します。
今回はSPAで作ります。

```
npx create-nuxt-app frontend
```

```npm run generate```実行後にビルドされたファイルをSpringBootプロジェクトの公開ディレクトリにファイルをコピーするために「cpx」をインストールします。

```
npm i cpx -D
```

ビルドコマンドを修正します。

```diff:frontend/package.json
- "generate": "nuxt generate"
+ "generate": "nuxt generate && cpx \"dist/**/*\" ../src/main/resources/static"
```

## GitHub Actions

まず、ワークフローの全貌です。以下の内容を記述したyamlファイルをプロジェクトルートの```.github/workflows```に作成します。yamlファイル名は自由です。今回はdeploy.ymlとしました。

```yml:.github/workflows/deploy.yml
name: WebAppDeploy

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [12.x]

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - uses: actions/cache@v1
      with:
        path: ~/.npm
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-
    - name: npm run generate
      run: |
        cd frontend
        npm install
        npm run generate
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - uses: actions/cache@v1
      with:
        path: ~/.m2/repository
        key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
        restore-keys: |
          ${{ runner.os }}-maven-
    - name: Build with Maven
      run: mvn -B package --file pom.xml
    - name: Generate build number
      id: buildnumber
      uses: einaregilsson/build-number@v1 
      with:
        token: ${{secrets.GITHUB_TOKEN}}
    - name: deploy
      uses: einaregilsson/beanstalk-deploy@v1
      with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY }}
          aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          application_name: githubactiondemo
          environment_name: demo
          version_label: ${{ steps.buildnumber.outputs.build_number }}
          region: ap-northeast-1
          deployment_package: target/githubactiondemo-0.0.1-SNAPSHOT.jar
```

今回は以下のプラグインを使いました。

- [einaregilsson/build-number](https://github.com/einaregilsson/build-number)
- [actions/cache](https://github.com/actions/cache)
- [einaregilsson/beanstalk-deploy](https://github.com/einaregilsson/beanstalk-deploy)


stepsの内容について説明します。

```yml
uses: actions/checkout@v1
```
ワークフローが、リポジトリ内のファイルにアクセスできるようになります。

```yml
- name: Use Node.js ${{ matrix.node-version }}
  uses: actions/setup-node@v1
  with:
    node-version: ${{ matrix.node-version }}
```
npmが使えるようになります。

```yml
- uses: actions/cache@v1
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-
```
npmの依存関係をキャッシュできます。これがないと、毎回ダウンロードすることになりビルドに時間がかかってしまいます。

```yml
- name: npm run generate
  run: |
    cd frontend
    npm install
    npm run generate
```
```cd frontend```でNuxtプロジェクトのルートに移動します。
```npm install```で依存関係をインストールします。
```npm run generate```で静的ファイルとして出力します。

```yml
- name: Set up JDK 1.8
  uses: actions/setup-java@v1
  with:
    java-version: 1.8
```
Java（jdk）が使えるようになります。今回はバージョン1.8を使います。

```yml
- uses: actions/cache@v1
  with:
    path: ~/.m2/repository
    key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
    restore-keys: |
      ${{ runner.os }}-maven-
```
Mavenの依存関係のキャッシュを利用できます。npm同様、毎回ダウンロードしなくて済みます。

```yml
- name: Build with Maven
  run: mvn -B package --file pom.xml
```
Mevenビルドを実行します。単純にコマンドを実行しているだけです。

```yml
- name: Generate build number
  id: buildnumber
  uses: einaregilsson/build-number@v1 
  with:
    token: ${{secrets.GITHUB_TOKEN}}
```
GitHub Actionsのビルド番号を取得できます。ElasticBeanstalkのデプロイ時に利用します。
```secrets.GITHUB_TOKEN```はデフォルトで設定されているので、意識する必要はありません。

```yml
- name: deploy
  uses: einaregilsson/beanstalk-deploy@v1
  with:
    aws_access_key: ${{ secrets.AWS_ACCESS_KEY }}
    aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    application_name: githubactiondemo
    environment_name: demo
    version_label: ${{ steps.buildnumber.outputs.build_number }}
    region: ap-northeast-1
    deployment_package: target/githubactiondemo-0.0.1-SNAPSHOT.jar
```
アプリケーションをElasticBeanstalkにデプロイできます。
```secrets.AWS_ACCESS_KEY```と```secrets.AWS_SECRET_ACCESS_KEY```は、予め設定しておく必要があります。

|項目|内容|
|:--|:--|
|aws_access_key|デプロイ権限のあるユーザのアクセスキー|
|aws_secret_key|デプロイ権限のあるユーザのシークレットキー|
|application_name|構築済みアプリケーション名|
|environment_name|構築済み環境名|
|version_label|デプロイバージョン|
|region|リージョン|
|deployment_package|アプリケーションのjar、またはzip|


## ワークフロー実行

今回はpush時に実行されるようになっているので、リポジトリにpushします。
push後、GitHubの対象リポジトリのActionsタブを開くと、ワークフローが実行されているのが確認できます。
```Complete Job```まで完了したら、ElasticBeanstalkの公開URLにアクセスし確認します。