第2の人生の構築ログ

自分の好きなことをやりつつ、インカムもしっかりと。実現していく過程での記録など。読書、IT系、旅行、お金に関係する話などの話題。

Google App Engine (GAE) を使って Go Web アプリ/静的 Web コンテンツを公開する (その1)

f:id:dr_taka_n:20190919112129p:plain:w500

Google Cloud Platform (GCP) が提供するアプリケーションの実行環境 Google App Engine (GAE)。最近はあまり言われなくなってきましたが、所謂 PaaS (Platform as a Service) と言われる環境です。今では実行環境の運用を考慮する必要のない「サーバーレス」環境といったほう通じるのかもしれません。アプリの実装の部分だけに注力でき、アプリを動作させるためのサーバ環境は GAE が用意するので、開発者は構成ファイルを記述するだけで Web アプリをリリースすることができます。

cloud.google.com

例えば、Web アプリを用意するためには、通常、サーバの OS 環境、その上にのっかってくるミドルウェア、AP サーバなどを用意する必要があり、アプリの実装以外のもの、インフラエンジニアの知識も必要となります。そこは GAE が用意してくれているものをそのまま使い、構成(設定)ファイルだけをちょこちょこといじるだけで Web アプリを動作させることが可能となる環境です。手軽なだけではなく、本格的な環境としてのスケーラビリティなどもお任せできるというステキな環境です。

Web アプリでなくても、静的 Web コンテンツもそのまま配置することで公開することができます。

ローカル環境で Web アプリを実装、実際に動作させながら開発を行い、公開はコマンド一発で実行できます。至れり尽くせりですね。

ここでは、GAE で Go を使った Web アプリの公開、ついでに静的ファイルも静的ファイルとして公開する方法のメモを残しておきます。

なお、おぉ便利!と思っても試すのにお金が必要となるとなかなか気軽に試すこともできませんが、そこは Google、あるレベルまでは料金はかかりません。ちなみに、ここに記載してあることを試すレベルでは課金対象とはなりません。

この GAE 環境には、スタンダード環境とフレキシブル環境の2つの実行環境があります。

cloud.google.com

現時点での違いは以下のように書かれています。

f:id:dr_taka_n:20190918145715p:plain

ここではスタンダード環境を使います。
また、前提として、Google Cloud SDK は既にインストールされているものとします。Cloud SDK を用意されていない方は以下のページを参考に用意しておいてください。

cloud.google.com

最初に Cloud SDK をアップデートしておきます。

$ gcloud components update

また、ここでは、Go を使いますので、GAE の Go 用の App Engine 拡張機能を含む gcloud コンポーネントをインストールしておきます。

$ gcloud components install app-engine-go

ここで使う材料のベースとなるサンプルソースは以下で公開されているものになります。

とてもシンプルな Go Web アプリを用意します

まずは2ファイルからです。GAE の構成(設定)ファイルであるapp.yamlと Go Web アプリの実装 helloworld.go です。

ちなみに、Go の場合は Web サーバも標準パッケージに組み込まれていますので、Web アプリの実装とは別に Web App サーバを用意する必要はありません。helloworld.go の実装の中に Web アプリ自体の実装、Web アプリサーバの実装が入っています。

$ ll
total 16
-rw-r--r--  1 hoge  staff   15  9  8 14:17 app.yaml
-rw-r--r--  1 hoge  staff  478  9  8 14:40 helloworld.go

構成ファイル app.yaml にはまずは必要最低限の設定のみを行います。go112 環境が既に使えるのですが、SDK のローカル環境での実行で一部制限がありますので、go111 を使います。

app.yaml 

runtime: go111

cloud.google.com

Go Web アプリの実装です。/hello のパスの呼び出しで indexHandler が実行され、"Hello, World!" を表示するだけのものものです。

helloworld.go

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/hello" {
        http.NotFound(w, r)
        return
    }
    _, err := fmt.Fprintf(w, "Hello, World!")
    if err != nil {
        http.Error(w, fmt.Sprintf("something wrong: %s", err), http.StatusInternalServerError)
    }
}

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

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

    log.Printf("Listening on port %s", port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}

まずはこの状態で GAE は関係なく、Go の仕組みの中だけで問題なく動作するか確認します。

サーバを起動します。

$ go run helloworld.go
2019/09/08 14:40:59 Defaulting to port 8080
2019/09/08 14:40:59 Listening on port 8080

curl でリクエストしてみます。

$ curl -X GET http://localhost:8080/hello
Hello, World!

問題ないですね。

ローカル開発用環境で動作確認する

今度は GAE の要素も入れてローカルで動作確認します。

アプリケーションを GAE 環境に公開(デプロイ)する前にローカル環境で実行/シミュレートできるローカル開発用サーバー(dev_appserver.py)が Clould SDK に入っていますので、こちらを活用します。

構成ファイル app.yaml を読み込ませて起動します。

$ dev_appserver.py app.yaml
INFO     2019-09-09 13:04:08,302 devappserver2.py:224] Using Cloud Datastore Emulator.
We are gradually rolling out the emulator as the default datastore implementation of dev_appserver.
If broken, you can temporarily disable it by --support_datastore_emulator=False
Read the documentation: https://cloud.google.com/appengine/docs/standard/python/tools/migrate-cloud-datastore-emulator
Help us validate that the feature is ready by taking this survey: https://goo.gl/forms/UArIcs8K9CUSCm733
Report issues at: https://issuetracker.google.com/issues/new?component=187272

INFO     2019-09-09 13:04:08,311 devappserver2.py:278] Skipping SDK update check.
INFO     2019-09-09 13:04:08,494 datastore_emulator.py:155] Starting Cloud Datastore emulator at: http://localhost:21024
INFO     2019-09-09 13:04:09,993 datastore_emulator.py:161] Cloud Datastore emulator responded after 1.500299 seconds
INFO     2019-09-09 13:04:09,996 api_server.py:275] Starting API server at: http://localhost:52058
INFO     2019-09-09 13:04:10,004 api_server.py:265] Starting gRPC API server at: http://localhost:52060
INFO     2019-09-09 13:04:10,007 instance_factory.py:180] Building with dependencies from GOPATH.
INFO     2019-09-09 13:04:10,079 dispatcher.py:256] Starting module "default" running at: http://localhost:8080
INFO     2019-09-09 13:04:10,081 admin_server.py:150] Starting admin server at: http://localhost:8000
/Users/hoge/Tool/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/mtime_file_watcher.py:182: UserWarning: There are too many files in your application for changes in all of them to be monitored. You may have to restart the development server to see some changes to your files.
  'There are too many files in your application for '
2019/09/09 13:04:14 Listening on port 19835
INFO     2019-09-09 13:04:15,685 instance.py:294] Instance PID: 72588

うまく起動しているようです。いろいろサービスがあがっているようですが、 INFO 2019-09-09 13:04:10,079 dispatcher.py:256] Starting module "default" running at: http://localhost:8080 から自身の web app は、8080 ポートのようです。確認してみます。

$ curl -X GET localhost:8080/hello
Hello, World!

OKです。

この環境、結構便利です。Go のソースコードを変更したら動的に読み直してくれて、サーバの上げ下げの必要もありません。起動したらコーディングに集中するだけです。

デプロイ(公開)します

GAE 環境にデプロイ(公開)するためには、他のサービス同様、プロジェクト(ID)が必要になります。また、そのプロジェクトに対して課金が有効となっている必要があります。

ここでは、前提としてこれらの事前準備は終えていることとします。詳細は以下のガイドなどを参照ください。

cloud.google.com

ではデプロイします。

$ gcloud app deploy

これだけです。

Services to deploy:

descriptor:      [/Users/hoge/Repos/gcp-gae-go-webapp-sample/app.yaml]
source:          [/Users/hoge/Repos/gcp-gae-go-webapp-sample]
target project:  [test-pro-1]
target service:  [default]
target version:  [20190911t222948]
target url:      [https://test-pro-1.appspot.com]


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

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 0 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.                                                                                                                                                                                              
Setting traffic split for service [default]...done.                                                                                                                                                                             
Deployed service [default] to [https://test-pro-1.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

うまくいっているようです。最後のメッセージ通り、ブラウザを起動して確認してみます。

$ gcloud app broswe

f:id:dr_taka_n:20190918154413p:plain:w500

ちゃんと Hello, World! を拝むことができました。OK です。

1記事としては長くなってきましたので、この後は「その2」で記載します。

続きは、以下を予定しています。

  • Go アプリ以外の静的コンテンツの公開
  • Go テンプレートの利用