【Google Cloud】サンプルコードを使ってApp Engineにアプリをデプロイしてみた

# はじめに

Google App Engineとは、Google Cloudで使用できるサーバーレスサービスです。
作成したソースコードとApp Engineの構成ファイルをデプロイすることで、容易にWebアプリケーションを開発することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/ed8de6d7-e29e-bc87-4613-f9ddf94899ba.png)
本記事ではGoogle社が提供しているサンプルコードを使用してアプリをデプロイするなど、App Engineの基本的な操作を実施してみました。

# 1. アプリ構成
## 1-1. ソースコード

App EngineでWebアプリケーションとして動作させるプログラムは、下記の言語をサポートしています。

|言語|スタンダード環境|フレキシブル環境|
|---|---|---|
|Python|○ (2.7、3.7、3.8、3.9、3.10)|○|
|Java|○ (8、11、17)|○|
|Node.js|○ (10、12、14、16)|○|
|PHP|○ (5.5、7.2、7.3、7.4、8.1)|○|
|Ruby|○ (2.5、2.6、2.7、3.0)|○|
|Go|○ (1.11、1.12、1.13、1.14、1.15、1.16)|○|
|.Net|×|○|

※本記事を投稿した時点での対応表となります。
※App Engineを使用するうえで、*スタンダード環境* か *フレキシブル環境* のどちらかの環境を選択してアプリを構築します。
これらの環境の詳細な違いについては本記事では解説しないため、Google Cloudが公開している[App Engine 環境に関するドキュメント](https://cloud.google.com/appengine/docs/the-appengine-environments?hl=ja)をご確認ください。

## 1-2. 構成ファイル

App Engineで動作するアプリの構成ファイルは、下記があります。

|ファイル名|必須であるか|説明|
|---|---|---|
|app.yaml|必須|App Engineで動作するアプリの設定を構成するファイルです。|
|cron.yaml|任意|アプリを定期的に(時刻／一定間隔)実行するためのスケジュール情報を設定します。|
|dispatch.yaml|任意|リクエストに指定されたURLのパスやホスト名に応じてルーティング先を設定できます。|
|index.yaml|任意|アプリがDatastoreクエリを使用するために必要なインデックス情報を設定します。|

# 2. 実践

それでは実際にApp Engineにデプロイし、サンプルコードを動かしてみます。
今回はCloud Shellを使用しての説明となります。

はじめに、Google Cloudコンソール上でCloud Shellを起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/724a224e-59cc-16ff-1a68-9cd2b4e03701.png)
下記のようにCloud Shellが起動すれば大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/a01aa71c-c379-4e7b-1c90-e14f421ee1c4.png)

## 2-1. アプリ作成

Google Cloudのプロジェクト内でApp Engineのアプリを作成します。
Cloud Shellのターミナル上で下記のコマンドを実行し、表示内容に従ってアプリを作成するリージョンを選択します。
```
gcloud app create --project=<PROJECT_ID>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/edc45cb9-cd22-8d87-1399-5d0c682eed8a.png)
自分はリージョン「asia-northeast1」を選択してみました。

Cloud Shellでgcloudコマンドを実行した際、下記のようにCloud Shellの承認を求められることがあります。
その場合は「承認」をクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/a312839a-c460-922d-0a9f-f87ee6df3fda.png)

## 2-2. サンプルコードのクローン

次に、本記事で使用するサンプルコードをGitHubからクローンします。

下記のコマンドを実行します。
```
git clone https://github.com/GoogleCloudPlatform/golang-samples.git
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/29e036ee-6a48-40c6-0745-03edb32fcedb.png)
クローン後、`golang-samples`というディレクトリがあることを確認してください。

## 2-3. デプロイ

クローンが正常に完了したら、サンプルコード内に同梱されている HelloWorld プログラムをApp Engineのアプリにデプロイします。

`cd`コマンドを使用して、`golang-samples/appengine/go11x/helloworld/` に移動します。
```
cd golang-samples/appengine/go11x/helloworld/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/0d70a796-ff3a-4529-3b6e-637f3e50535f.png)
移動後、`ls` コマンドでディレクトリ内のファイルを確認すると、いくつかファイルが出てきました。

- app.yaml
    - App Engine 構成ファイル
    サンプルコードに同梱されているこの構成ファイルには、アプリで使用されるランタイム環境が指定されています。
    「runtime: go115」と記載されており、Goの1.15が指定されています。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/b329c0ba-c67e-b560-039b-825ad41dfc3d.png)
- go.mod
    - プログラムモジュールの依存関係をまとめた管理ファイル
- go.sum
    - チェックサムという方法でプログラムモジュールの信頼性を確認するための管理ファイル
- helloworld.go
    - App Engineで動作するプログラム
    アプリのURLにアクセスすると「Hello, World!」という文字列を出力するGo言語のプログラムです。
- helloworld_test.go
    - `helloworld.go` のテストコード

上記のファイルをApp Engineにデプロイします。
同じディレクトリ内で下記のコマンドを実行します。
```
gcloud app deploy
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/625b0f59-ab4d-0a33-92a6-d7202f540110.png)
コマンドを実行すると、デプロイ内容が表示されます。

※特に指定がない場合、「default」というサービス名で作成されてデプロイされます。
任意の名前でサービスを作成する場合、`app.yaml` でサービス名を指定する必要があります。

デプロイ内容を確認し、問題がなければ「y」を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/07e424d0-5192-c391-e86f-ba64a6c925cf.png)
デプロイが正常終了したようです。

## 2-4. 動作確認

Google Cloudコンソール上でApp Engineの管理画面を表示し、左側のメニューバーから「サービス」をクリックすると、先ほどデプロイしたアプリが登録されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/b1c82f03-edf2-dee2-d730-36b734abd7f2.png)
「default」をクリックすると、ブラウザの別タブが開き、`Hello, World!`という文字列が出力されることを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/9f761894-03b8-e01a-4eb3-64808b3ad782.png)

# 3. サービス名を変更してデプロイしてみた
 
上記の操作でデプロイし、アプリの動作を確認できました。
しかし、登録するサービス名を自分で設定しないと、デフォルトでサービス名が「default」で登録されてしまいます。
自分の好きなサービス名で登録したい場合もあると思うので、そちらについても実施してみます。

先ほど紹介したApp Engineの構成ファイル `app.yaml` でサービス名を指定することができます。

Cloud Shell上で `golang-samples/appengine/go11x/helloworld/` ディレクトリにある `app.yaml` を開き、下記の内容を追記します。
```
service: <SERVICE_NAME>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/cb33ca1d-c87c-cd24-ae5d-1d0f87fa7783.png)
この状態でファイルを保存し、gcloudコマンドを使用して再度アプリをデプロイします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/aa4ad836-c038-7e8f-a22e-aa6e4f3aa138.png)
`target service` と `target url` が指定したサービス名に設定されていることを確認できます。

デプロイ完了後、再度Google Cloudのコンソール画面でApp Engineのサービス一覧を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/c7ae0645-ff0d-89b5-ff8a-ac9d8755064e.png)
先ほどの手順でデプロイした「default」サービスとは別に、新しくサービスが登録されました。

今回は　`app.yaml` で `service` の値を設定してサービス名を指定してみましたが、
他にもサービスのスケーリングに関する設定やハンドラ要素の設定等が行えます。
詳細はGoogle Cloudが公開している[app.yaml 構成ファイルのドキュメント](https://cloud.google.com/appengine/docs/standard/go/config/appref?hl=ja)をご確認ください。

※補足
サービス名を指定せずデプロイした際に「default」という名前でサービスが登録されると前述しましたが、どうやら<INS>「default」という名前のサービスを削除することはできない</INS>ようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/368e8066-321c-a498-47c2-73daf9414a54.png)
「default」サービスをどうしても削除したい場合、プロジェクトごと削除するしかなさそうです。

# 4. バージョン管理機能に触れてみた

App Engineで動作するアプリのソースコードや構成ファイルを更新する際、
稼働中の内容に更新済みの内容を上書きするのではなく、
最新の内容、1つ前の内容、2つ前の内容、... のように、アプリをバージョン管理することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/fc93e388-9018-7f16-3339-24d225e5a68c.png)
先ほどの手順でデプロイした HelloWorld プログラムを少し修正して再度デプロイし、
バージョンが追加されることを確認してみます。

Cloud Shell上で `helloworld.go` を開き、「Hello, World!」と出力している処理の出力内容を任意の文字列に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/5b7f0805-d715-e4de-b004-c226b96a87d5.png)
ソースコード修正後、先ほどの手順と同様にアプリをデプロイし、Google Cloudコンソールでサービス一覧を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/9635e40b-fbc9-ad39-5649-4f4c2f36097a.png)
すると、当該サービスのバージョンが `2` になっていることを確認できます。
再度デプロイしたアプリのURLにアクセスすると、出力される文字列が変わっていることも確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/46bf5979-518c-c191-30b6-e4c9cf9bb1f7.png)

バージョンの管理画面を見てみます。
App Engine画面の左側のメニューバーから「バージョン」をクリックすると、下記のような画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/8a285992-06e2-0c32-d6b4-774cba402a37.png)
「サービス」というプルダウンでサービスを選択すると、該当するサービスのバージョンが一覧表示されます。
上記画像の「20220714t121237」が最初にデプロイしたバージョンで、
「20220714t121929」がソースコードを修正して再デプロイしたバージョンですね。

バージョンごとに受信するトラフィックを分割することもできるようです。
画面右上の「トラフィックを分割」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646497/ce42f15b-976d-f200-b41f-2cad17c9f800.png)
トラフィック分割の基準、トラフィックを分割する割合を設定することができるようです。

以上、App Engineの基本的な機能を触れてみたので、本記事にまとめてみました。

# 参考資料
[クイックスタート App Engine](https://cloud.google.com/appengine/docs/standard/go/create-app)
[App Engine 構成ファイル ドキュメント](https://cloud.google.com/appengine/docs/standard/go/config/appref?hl=ja)
[App Engine 環境に関するドキュメント](https://cloud.google.com/appengine/docs/the-appengine-environments?hl=ja)
[サンプルコード公開Github](https://github.com/GoogleCloudPlatform/golang-samples)