GitHub Actionを利用して、リリースタグを作成した後自動的にGoogle Cloud App Engineデプロイする

## はじめに
株式会社ピーアールオー（あったらいいな！を作ります） Advent Calendar 2022の10日目になります。
前日は「[Salesforce]問い合わせページにWeb-to-リードを設定する 」でした。
さらに7日目は「SpringBoot MVCで簡単なWEBアプリを実装してみる」でしたので、今回は実際作ったWEBアプリをGoogle Cloud App Engineにデプロイしようと思っています。

## 事前準備
まずはJavaベースのWEBアプリを用意する必要があります。今回はSpringBootのかわりに、[Quarkus](https://quarkus.io)を利用します。
Quarkusコマンドを利用するので、[Quarkusコマンドのインストール方法](https://quarkus.io/guides/cli-tooling)はこちらになります。

Quarkusコマンドをインストール完了後、`quarkus create app`のコマンドでアプリを作成します。

```bash
quarkus create app medium-demo-app

-----------

applying codestarts...
📚  java
🔨  maven
📦  quarkus
📝  config-properties
🔧  dockerfiles
🔧  maven-wrapper
🚀  resteasy-reactive-codestart

-----------
[SUCCESS] ✅  quarkus project has been successfully generated in:
--> /medium-demo-app
-----------
```
作成したプロジェクトを開き、新しい「TopResource」の名前のクラスを追加します。クラスの内容は以下になります。

```java
package org.acme;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/")
public class TopResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello, this is a demo website for medium story.";
    }
}
```

次は、下記のコードを`application.properties`ファイルに追加します。

```java
quarkus.package.type=uber-jar
```

終わったら、ローカル環境で確認します。まずはアプリをコンパイルします。

```bash
quarkus dev
```

ビルドが終わったら、ブラウザを開き、`http://localhost:8080`にアクセスします。

![Screenshot from 2022-12-08 23-40-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/d2714eb5-3476-98f2-d151-a8a998a8d79c.png)

## App Engine Applicationを用意する
次は新しいGCPプロジェクトを1個作成し、App Engineアプリを作成します。

![Create App Engine Application](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/0fd1fc32-5a47-f041-6509-7ac8b29be5c3.png)

![Select a Region](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/4fcb309f-38ee-5c4f-6f17-c6b73f963e1b.png)

![Screenshot from 2022-12-08 23-48-04-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/df924066-d981-01ac-eb46-d9a9c8b9da57.png)

## 必要なAPIを有効にする
今回は下記の2つのAPIが必要となります。
- App Engine Admin API
- IAM API

APIのダッシュボード画面に遷移し、必要なAPIを検索し、有効にします。

![API Dashboard](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/1bace9c1-f4fe-9d7d-8d05-0a28dc827e44.png)

![Enable API](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/58cf806b-5a14-81cf-1490-299f20a1e21e.png)

## Deploy専用のアカウントを作成する
IAM & Adminから「Service Account」画面に遷移し、新しいサービスアカウントを作成します。

![Create a service account](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/32fc3c26-653d-be05-32a4-401469716cf4.png)

アカウント作成したら、デプロイするため必要なロール情報をさくせいしたアカウントに付与します。

![Add Roles](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/12898e1d-9a0d-562a-00d3-4272c8868f0d.png)

必要なロール権限は下記の4つです。
- App Engine Admin
- Service Account User
- Storage Admin
- Cloud Build Editor

ロール権限を付与したら、次は認証用のキーを1個新規追加します。サービスアカウント一覧から作成したアカウントもメールアドレスをクリックし、「Key」のタブを選択します。新しいJSONタイプをキーを新規作成します。終わったら、1個JSONファイルをダウンロードされるはずです。このファイルは後で利用します。

![Screenshot from 2022-12-09 00-10-26-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/7af5be43-da15-ac14-7402-bd7034b38f67.png)

## GitHub Actionの作成
まず、GitHubに1個新しいリポジトリを作成し、さっき用意したQuarkusのソースコードをリモートブランチにプッシュします。

次、プロジェクトロートフォルダの下に「.github/workflows」のフォルダを作ります。その中に1個「google-deploy-app-engine-source.yml」の名前のymlファイルを作ります。ファイル名は任意です。

### GitHub Actionの実行タイミングの定義

まずは作成したymlファイルに下記のコードを追加します。

```yaml
name: Deploy to App Engine from Source

on:
  push:
    tags:
      - 'v*'
```

今回は特定のブランチにマージされた後ではなく、リリースタグを作成したらデプロイしたいです。今の定義は「v1.0.0」など「v」から始まりのタグがリモートリポジトリにプッシュされたら、定義したジョブは動きます。

次はジョブの詳細内容を定義します。

### GCPへの認証

まずはデプロイユーザー認証が必要なので、GCPユーザー認証の部分を先に記載します。

```yaml
jobs:
  job_id:
    permissions:
      contents: 'read'
      id-token: 'write'

    runs-on: ubuntu-latest
    steps:
      - uses: 'actions/checkout@v3'

      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@v1'
        with:
          credentials_json: '${{ secrets.GCP_SA_KEY }}'
```

続いて、リポジトリの設定から新しい「Repository Secret」の値を追加します。値名はymlファイルに記載した「GCP_SA_KEY」になります。値はさっきダウンロードしたJSONファイルの中身になります。

### gcloudコマンドのセットアップ

gcloudコマンドを利用してデプロイしますので、次はGoogle Cloud SDKのセットアップします。
ymlファイルに次のコードを追加します。

```yaml
      - name: 'Set up Cloud SDK'
        uses: 'google-github-actions/setup-gcloud@v1'
```

### Jarファイルの作成

次はWEBアプリをビルドし、実行可能なJarファイルを作成します。

```yaml
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: maven

      - name: Build App
        run: mvn clean package
```

### App Engineにデプロイ

最後はgcloudコマンドをりようして、App Engineにデプロイします。

```yaml
      - name: Deploy to App Engine
        id: deploy
        run: gcloud app deploy ${{ github.workspace }}/target/medium-demo-app-1.0.0-SNAPSHOT-runner.jar

```

### yamlの全体

```yaml
name: Deploy to App Engine from Source

on:
  push:
    tags:
      - 'v*'

jobs:
  job_id:
    permissions:
      contents: 'read'
      id-token: 'write'

    runs-on: ubuntu-latest
    steps:
      - uses: 'actions/checkout@v3'

      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@v1'
        with:
          credentials_json: '${{ secrets.GCP_SA_KEY }}'

      - name: 'Set up Cloud SDK'
        uses: 'google-github-actions/setup-gcloud@v1'

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: maven

      - name: Build App
        run: mvn clean package

      - name: Deploy to App Engine
        id: deploy
        run: gcloud app deploy ${{ github.workspace }}/target/medium-demo-app-1.0.0-SNAPSHOT-runner.jar
```

ymlファイルの編集が終わったら、リモートリポジトリにプッシュします。

## GitHubにリリースタグを作成
最後はGitHub上で1個リリースタグを作成し、GitHub Actionの動きを確認します。

問題がなければ、GCPのApp Engineの管理画面に1個新しいサービスが追加され、そのサービスのURLをクリックすると、ローカルで確認した画面と同じ内容がひょうじされます。

![Screenshot from 2022-12-09 02-35-49-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925109/1f35cc87-106c-c41d-8aaf-9f46099aeb4b.png)

## 最後に
今まで開発者が手動で色々メンドな作業しないと行けない部分を、今回はGitHub Actionを利用し自動的にやってくれます。さらにGitHub Actionの方にある他の機能(テスト実行や、カバレッジの計算など)との組み合わせで、更に開発効率が上がります。

## References
- 英語版の記事: https://medium.com/@lxlgarnett/deploy-a-java-app-to-google-cloud-app-engine-auto-by-create-git-tag-using-github-action-1401e4c30faa