前提条件
- Goでgin-gonic frameworkでアプリを作る
- ローカルではIntelli-J IDEを使って開発し、起動し、ソースレベルデバッグしたい
- サーバーは、Google App Engine(GAE)上で動かす
- ginのLoadHTMLGlobでtemplateをロードできるようにする
GAEのデプロイに関する話
- app.yamlファイルにGAEで動かすための設定をいろいろ書く
- GAEは特殊でinit()という関数が最初に呼ばれる
- mainパッケージのmain()があるgoファイルを含んではならない
- もしあると、このようなエラーが出てデプロイできない
RuntimeError: 2016/12/04 12:06:47 go-app-builder: Failed parsing input: parser:
found a top level package main with function main,
but main does not call appengine.Main();
see https://godoc.org/google.golang.org/appengine#Main for more information
- app.yamlと同一フォルダにあるファイルおよびディレクトリがアップロード対象になる
Intelli-Jの話
- mainパッケージのmain()関数がないと起動できない
- つまりローカル開発ではmainパッケージのmain()関数が必要
ハマる問題
- mainパッケージがデプロイ対象にならないようにする必要がある
- app.yamlのskip_filesに書いてもだめ
- go buildのtagオプションで切り分けるのもだめ
- app.yamlと同じディレクトリに、テンプレートファイルがないと、router.LoadHTMLGlob()でテンプレートファイルロードに失敗する。以下のようなエラーが出る
html/template: pattern matches no files: `./templates/**/**/*`
フォルダ構成
- main.go
- app/
- controllers/
- models/
- app_init.go
-
gae/
- app.yaml
- init.go
- templates/
- home/
- index.tmpl
- home/
- static/
- hoge.js
- hoge.css
- appフォルダはアプリに関するソースファイルおよびテンプレートを配置
- templatesはテンプレートファイル置き場
- staticフォルダは静的ファイル置き場
- gaeフォルダはGAEに関するファイル
- app/main.goは、mainパッケージでmain関数がある
- gae/init.goは、gaeパッケージでinit関数がある
- パッケージ名はmainでなければなんでも良い
main.goでもinit.goでも共通で初期化できるようにする。
app/app_init.go
package app
〜〜〜中略〜〜〜
func app_init(gae bool) *gin.Engine {
router := gin.Default()
// router.GET("/", root())とか
if !gae {
// GAEでないなら、ginのrouter.Static()でstaticディレクトリ指定
// GAEの時は、app.yamlに従う
router.Static("/static", "./gae/static")
}
if gae {
router.LoadHTMLGlob("./templates/**/**/*")
} else {
router.LoadHTMLGlob("./gae/templates/**/**/*")
}
return router
}
ローカルではポート指定してHTTPサーバー起動するところまで書く
main.go
package main
〜〜〜中略〜〜〜
func main() {
router := app.app_init(false)
router.Run(":5000")
}
GAEはrouter.Run()で起動しないことに注意
init.go
package gae
〜〜〜中略〜〜〜
func init() {
router := app.app_init(true)
http.Handle("/", router)
}
app.yamlにGAE上でのstaticディレクトリ参照を書く
app.yaml
application: myapp
version: v1
runtime: go
api_version: go1
handlers:
- url: /static
static_dir: static
- url: /.*
script: _go_app
ポイント
- main.goとinit.goを別のフォルダに置く
- Intelli-Jは、main.goのmain()を起点にして起動する
- GAE上ではinit.goのinit()が起点となり起動する
- それぞれテンプレートディレクトリまで適切なパスが渡るようにする
- GAEのデプロイコマンドは、gaeフォルダのapp.yamlを指定し、そのフォルダのファイル、ディレクトリがデプロイ対象になる
- templatesディレクトリもgaeフォルダ以下に置く
- デプロイコマンド例
$ appcfg.py update ./gae/app.yaml