Overview
Google App Engine 2ndGenにてapp.yamlの設定でmain property を指定して、mainで指定した path をプロジェクトの root として静的ファイル( static や template 配下のファイル)が正常に読み込めるかどうか調べました。
以前も静的ファイルのサーブに関連したエントリは書いたのですが、今回はそこからアップデートのあった内容も含めて記載してます。
main propertyについて
公式ドキュメントには以下のように記載されています。
Optional. The path or fully qualified package name of the main package.
You must declare the path to the main package if your package main is not in the same directory as your app.yaml. The main element supports file paths relative to app.yaml or full package names.
cf. app.yaml Configuration File | App Engine standard environment for Go 1.11 docs | Google Cloud
app.yamlの設定
以下のようなディレクトリ構成に置いて
├── app │ └── cmd │ └── main.go ├── app.yaml └── go.mod
app.yaml で main property に ./app/cmd
を指定することで、このアプリケーションにおける main package の path を設定します。
これにより app.yaml と main.go が同階層になくても main で指定されたディレクトリの main package が app.yaml と同階層にあるものとして読み込むことができます。
sample app.yaml
runtime: go111 service: gae-go111-app main: ./app/cmd
GAE 2nd Generation 以降はデプロイした時に CloudBuild でアプリケーションのビルドが行われるので、CloudBuild の実行ログから main package を ./app/cmd
に変更してるログを確認することができます。
Building /tmp/stagingXXXXXXXXX/srv, with main package at ./app/cmd, saving to /tmp/stagingXXXXXXXXX/usr/local/bin/start
正常に main が再設定されてる場合は上記のようなログが出力されます。
goのコードから静的ファイルを読み込む
実際に go のファイルの中で特定のファイルを開きたい、ようなケースがあった場合も main を指定することにより、main.go が app.yaml と違う階層にあった場合も、app.yaml がある階層をルートとして go のコードから呼ぶことができるようになります。
そのため、app.yaml を配置した階層と同じ階層に特定のファイルを配置して、そのファイルをダイレクトに指定する(相対パス等を考えなくていい)ことでファイルにアクセスすることができます。
具体的には ./src/app/cmd/main.go の内部で以下のような実装をしたとしても、app.yaml そのものが出力されます。
f, err := os.Open("app.yaml") if err != nil { panic(err) } io.Writer(os.Stdout, f)
templateを読み込む
go のコードから静的なファイルを読み込む時と同様に app.yaml があるディレクトリと同じ階層に template のディレクトリを作成し go のコードから相対パスなしで直接 template のファイルを指定することで読み込むことができます。
ディレクトリ構成は以下です。
├── app │ └── cmd │ └── main.go ├── app.yaml ├── go.mod ├── handler │ └── index.go └── templates └── index.tmpl
template を呼び出す側は変更ありません。
tmpl, err := template.ParseFiles("templates/index.tmpl") if err != nil { panic(err) } if err := tmpl.Execute(w, nil); err != nil { panic(err) }
static ファイルを読み込む
最後に js や css といったファイルのサーブの設定ついてですが、これは元々の設定と変わらず handler property で設定します。
/static/js/index.js
というファイルを読みたい場合は、app.yaml の static_dir に static を指定します。
ディレクトリ構成は以下
├── app │ └── cmd │ └── main.go ├── app.yaml ├── go.mod ├── handler │ └── index.go ├── static │ └── js │ └── index.js └── templates └── index.tmpl
sample app.yaml
runtime: go111 service: gae-go111-app main: ./app/cmd handlers: - url: /static static_dir: static secure: always
sample index.tmpl
{{ define "index.tmpl" }} <html lang="ja"> <head> <title>test</title> </head> <body> <p>hello world</p> </body> <script src="/static/index.js" ></script> </html> {{ end }}
これらを実際に設定してみて、デプロイすると template を読み込んだ時に一緒に js も読み込まれます。
※ localで go run ./PathTo/main.go
で起動した場合、static ディレクトリにルーティングされない(appengine を起動しないといけない) ので、デプロイするか、 dev_appserver.py app.yaml
で appengine を起動させてみての確認が必須です。
まとめ
app.yaml の main を指定することで 1st Generation の時のようなプロジェクト構成でも静的なファイルをサーブして読み込むことが可能です。
ref
- Migrating your App Engine app from Go 1.9 to Go 1.11 | App Engine standard environment for Go 1.11 docs | Google Cloud
- app.yaml Configuration File | App Engine standard environment for Go 1.11 docs | Google Cloud
コードはこちらに置いておきました。