アプリエンジニアでも簡単！Google App Engine(GAE)を使ってみよう！

# ▶ 「Google App Engine」 とは

[Google App Engine  |  Google Cloud](https://cloud.google.com/appengine/?hl=ja)

Google App Engine（以下、GAE）はフルマネージド型のサーバーレスプラットフォームです。
GAEを使うとインフラの管理を特に気にしなくて良くなるので、アプリの開発だけに集中できます。

公式では以下のように謳ってます。
> フルマネージド型のプラットフォーム上でアプリケーションを構築してデプロイしてください。
アプリケーションのスケールをゼロから地球規模まで拡大しても、基盤となるインフラストラクチャの管理について心配する必要はありません。
サーバーの管理も環境の構成も不要なため、開発者は優れたアプリケーションを構築することだけに集中でき、管理上のオーバーヘッドは発生しません。
App Engine では、よく利用されている開発言語と幅広いデベロッパー ツールがサポートされているため、デベロッパーは高い生産性と俊敏性（アジリティ）を維持できます。


# ▶ 前提条件
* プロジェクトを作成してあること
* Cloud Shellの使用方法をざっくり理解している
* golangをちょっとだけ知ってる (雰囲気でもok）

# ▶ やってみた
## ▽ ゴール

[Interactive Hello World in the App Engine Standard Environment with Go](https://console.cloud.google.com/start?tutorial=go_gae_quickstart)

こちらのチュートリアルを参考に触ってみました。

## ▽ 料金プランの確認

無料枠もありますし大丈夫かとは思いますが、念の為チュートリアルが始まる前にGAEの課金体系をチェックしておきます。

GAEには「[スタンダード環境](https://cloud.google.com/appengine/docs/about-the-standard-environment?hl=ja)」と「[フレキシブル環境](https://cloud.google.com/appengine/docs/flexible/?hl=ja)」の２つの環境があります。
どちらを利用するかで課金体系が違うので注意が必要です。

ざっくりとそれぞれの環境の用途を説明すると。。。

- スタンダード環境（SE）

```
    実行環境：　
        - サポートされている言語のランタイム環境を使用してサンドボックス内で実行
    課金：　
        - インスタンスの稼働時間に基づいて時間単位で課金される
    できること：　
        - 無駄な投資を抑え、無料または低コストで運用することができる (インスタンス数0にスケール可能)
        - トラフィックの緩急が激しい場合などの迅速なスケーリングをしたい時はこっち推奨
    所感：　
        - AWS EBっぽい？
```

- フレキシブル環境（FE）

```
    実行環境：　
        - Compute Engine仮想マシン（VM）上のDockerコンテナ内で実行
    課金：　
        - vCPU、メモリ、永続ディスクの使用量
    できること：　
        - リクエストの最大タイムアウトが60分と長いので、処理に時間がかかるものでも対応可能
        - ランタイムを変更することが可能
    所感：　
        - Amazon ECS on Fargateっぽい？
```

という感じで異なっています。
チュートリアルはどちらの環境を使ってやるかは別々になってますので問題ないですが、実際の開発をする際は要件と相談してご自身にあった環境を選ぶ必要があるので注意が必要です。(詳細「[App Engine 環境の選択](https://cloud.google.com/appengine/docs/the-appengine-environments?hl=ja)」)

とりあえず料金に関しては、困っても困らなくても「[料金計算ツール](https://cloud.google.com/products/calculator/?hl=ja#tab=app-engine)」を使って計算すれば安牌です。

## ▽ 「Hello, World!」アプリのビルドと実行
### サンプルアプリを準備する
料金体系も確認しましたので、ようやくチュートリアルを進めていきます。
適当なプロジェクトを選択したあとにCloud shell上でサンプルコードをcloneします。

```bash
$ git clone https://github.com/GoogleCloudPlatform/golang-samples

$ cd golang-samples/appengine/go11x/helloworld
```

移動した先の構成を確認してみると↓のような構成であることがわかります。

```bash
$ ls -r
helloworld_test.go  helloworld.go  app.yaml
```

これから試そうとしているサンプルアプリはコードを見ると分かる通り、ENVで指定したPORTにアクセスがあった場合「Hello, World!」と表示をしてくれるアプリのようですね。

```golang:helloworld.go
// ~ 前略 ~

func main() {
        http.HandleFunc("/", indexHandler)

        // [START setting_port]
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
                log.Printf("Defaulting to port %s", port)
        }

        log.Printf("Listening on port %s", port)
        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
        // [END setting_port]
}

// ~ 中略 ~

// indexHandler responds to requests with our greeting.
func indexHandler(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        fmt.Fprint(w, "Hello, World!")
}

// ~ 後略 ~
```

ところで、GAEではYAMLファイルを使用してデプロイの構成を指定します。
先程構成を確認した時にあった「app.yaml」には、ランタイム環境やURLハンドラ、その他のリソース設定を定義します。

構成オプションの全リストについては、[app.yaml リファレンス](https://cloud.google.com/appengine/docs/standard/go112/config/appref?hl=ja)にあるのでそちらを参照して頂くとして、今回はどのような情報が指定してあるかを確認していきます。

```yaml:app.yaml
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

runtime: go112 # replace with go111 for Go 1.11
```

今回はランタイム環境のみが設定されています。
先程確認したhelloworld.go内では「PORT」環境変数が必要だったと思いますが、もし定義していなくても「port = 8080」を設定するように回避策が採られているので一旦このまま進めます。

### サンプルアプリの動作を検証する
では次に、アプリをGAEにデプロイする前にアプリの動作を確認してみます。
Cloud Shell上で↓のコマンドを実行します。

```bash
$ go run .
```

すると↓のようなログが出たのではないでしょうか？

```
2019/11/15 14:45:23 Defaulting to port 8080
2019/11/15 14:45:23 Listening on port 8080
```

これが無事表示されれば起動はできていますが、まだ動作を検証していません。
Cloud Shellペイン上部にある「ウェブでプレビュー」ボタンをクリックしてブラウザでの動作テストをします。
![no1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318649/e028bd54-6544-9741-989e-90e899af0e99.png)

すると↓のように表示されたと思います。
これで動作検証はOKです。
<img width="1100" alt="no2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318649/db189b9d-8c39-f154-f13c-c94573cd0eb1.png">


なお、この動作検証に利用しているインスタンスはCloud Shellで「Ctrl+C」キーを押せばインスタンスが終了されます。

### GAEにデプロイする

ようやくGAEにデプロイしていきます。
しかし、GAEにアプリ（ややこしいのでデプロイしたいアプリのことを以降「*APP*」と書きます）をデプロイする為に、まずデプロイ先となるGAEアプリケーションがなくてはなりません。 
(既にある方は省略して大丈夫です)

というのも、APPは実際にGAEで提供する時には「**Service**」に属する「**Version**」という形となって提供され、「**Service**」は「**GAEアプリケーション**」に**n:1**で属するものだからです。
これはAWSでいうECSに似ていますね。

↓構成図（[公式](https://cloud.google.com/appengine/docs/standard/go111/an-overview-of-app-engine?hl=ja)）を見ると全体像がわかります。
<img src="https://cloud.google.com/appengine/docs/images/modules_hierarchy.svg?hl=ja">

閑話休題。

まだGAEアプリケーションを作ってない方は作る必要があるので、まずはアプリケーションを作成する必要があるのでやっていきましょう。

GAEアプリケーションを作成するために↓のコマンドを実行して、どこのリージョンにアプリケーションを作るか選択します。
リージョンについては[こちら](https://cloud.google.com/appengine/docs/locations?hl=ja)を参考にどうぞ。
なお、今回は特に理由はないですが東京リージョンを選択しました。

```bash
$ gcloud app create
You are creating an app for project [xxxx].
WARNING: Creating an App Engine application for a project is irreversible and the region
cannot be changed. More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.

Please choose the region where you want your App Engine application
located:

 [1] asia-east2    (supports standard and flexible)
 [2] asia-northeast1 (supports standard and flexible)
 [3] asia-northeast2 (supports standard and flexible)
 [4] asia-south1   (supports standard and flexible)
 [5] australia-southeast1 (supports standard and flexible)
 [6] europe-west   (supports standard and flexible)
 [7] europe-west2  (supports standard and flexible)
 [8] europe-west3  (supports standard and flexible)
 [9] europe-west6  (supports standard and flexible)
 [10] northamerica-northeast1 (supports standard and flexible)
 [11] southamerica-east1 (supports standard and flexible)
 [12] us-central    (supports standard and flexible)
 [13] us-east1      (supports standard and flexible)
 [14] us-east4      (supports standard and flexible)
 [15] us-west2      (supports standard and flexible)
 [16] cancel
Please enter your numeric choice:  2

Creating App Engine application in project [xxxxxxx] and region [asia-northeast1]....done.
Success! The app is now created. Please use `gcloud app deploy` to deploy your first app.
```

これで受け入れ先ができましたのでデプロイができるようになりました。
Cloud Shellで↓のコマンドを実行してデプロイしてみましょう。
(デプロイがされるまで数分時間がかかります)

```bash
$ gcloud app deploy
Services to deploy:

descriptor:      [/home/dmzsecondly/golang-samples/appengine/go11x/helloworld/app.yaml]
source:          [/home/dmzsecondly/golang-samples/appengine/go11x/helloworld]
target project:  [xxxx]
target service:  [default]
target version:  [20191115t153942]
target url:      [https://xxxxx.appspot.com]


Do you want to continue (Y/n)?  Y

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1049 files to Google Cloud Storage             ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://xxxxx.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse
```

これでAPPがデプロイされました！
デプロイしたアプリの「デフォルトURL」は「プロジェクト ID」で始まる appspot.com のサブドメインとなります。

ex. xxxxx.appspot.com

早速確認してみましょう！

```bash
$ gcloud app browse
```

![no3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318649/4ae2e0a4-73b7-3bfb-67ed-16a31df83b14.png)

ちゃんと動作していることが確認できました！


### アプリの状態を確認する

アプリのステータスはダッシュボードで確認することができます。
URIごとの負荷だけじゃなくて課金ステータスとかも一目瞭然なので是非活用していきたいところです。
![no4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318649/399a54ac-439a-e10a-fbbf-c9abc7f62bfb.png)


## ▽ チュートリアルの後のお片付け

では最後にお片付けをしていきます。
このアプリの課金を停止するには↓の2つしかありません。

- アプリケーションを無効
- プロジェクトを削除

今回は「アプリケーションの無効化」をやっていきたいと思います。
アプリケーションを無効化した時の詳細は[公式にある「アプリケーションの無効」](https://cloud.google.com/appengine/docs/standard/java/console/?hl=ja)という項目を見ていただければわかりますが、実行しているインスタンス等を停止して使えなくするだけなので、対象プロジェクト自体で使っている他のサービスの課金が止まるわけではないのでそこだけご注意を。

無効化の手順は簡単で↓のようにすればOKです。
![no5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318649/1fc19f33-b743-4d8f-ce84-2cd9ace3d4d4.png)


# ▶ 感想

よくあるWebサービスの構成を考慮して作るときは↓のような資料を読んでおく必要はあると思いますが、簡単なアプリならインフラを気にせずすぐに作れるので簡単でした！
12ヶ月の無料枠が終わっても毎月フリーで使える分があるようなので、開発者が試しに色々やるのとかホントに小さなサイトを初めて見るのだととてもいいのではと思いました！

[App Engine の概要](https://cloud.google.com/appengine/docs/standard/go111/an-overview-of-app-engine?hl=ja)
[App Engine でのウェブサービスの構造化](https://cloud.google.com/appengine/docs/standard/go111/configuration-files?hl=ja)