GoもGAEも不慣れな状態でやってみたら、タイミングもあって色々ハマったのでまとめました。
マサカリやもっといい方法があればぜひコメントください。
変更履歴
- ※Go1.8に対応
目的
- GAEのアプリをリリースしたい
- テストも書きたい
- ローカルでの動作確認もしたい
- 外部ライブラリ使いたい
- DataStoreやQueueを使いたい
環境
- GAE/Go standard environment (go1.8.3)
- Google Cloud SDK 167.0.0
- app-engine-go
サンプルのソースコードはこちら。
https://github.com/uryyyyyyy/GAESample
GAEアプリのディレクトリ構成
ディレクトリ構成
色々悩んだ結果こうなりました。
$ tree .
.
├── app
│ ├── gae_service1
│ │ ├── local.yaml
│ │ ├── main.go
│ │ └── prod.yaml # stg.yamlも必要があれば
│ ├── gae_service2
│ │ ├── local.yaml
│ │ ├── main.go
│ │ └── prod.yaml
│ └── other_application # GAE以外にgoアプリがあれば
│ └── main.go
├── bin # GAE以外のアプリのバイナリ置き場など
├── commands # 各種コマンド置き場
├── src # 自分で書いたコード
│ ├── gae_service1 # 各サービスでのみ使うコードとか
│ ├── gae_service2
│ ├── other_application
│ └── utils # 共有したいコードとか
└── vendor
├── glide.lock
└── glide.yaml
Commands
Makefileは個人的に使いにくかったのでshellベースにして、commandsフォルダ以下に置きました。
処理内容はお好みですが、共通部分としてGOROOT、GOPATHなどの設定をしています。
export GOROOT=$(dirname $(which dev_appserver.py))/../platform/google_appengine/goroot-1.8
export GOPATH=`pwd`:`pwd`/vendor
export GAE_ROOTDIR=`pwd`
GOROOTは見ての通りで、GAEでの動作環境に合わせています。
GOPATHは、src以下を入れるのは良いとして、vendorを普通のGoアプリのようにsrc直下に置くと gocloud app deploy
コマンドがうまく動かないためワークアラウンドとして避けています。いいやり方があれば知りたい。
コマンドの具体的な内容としては、例えば
- ローカルでのGAEアプリのrun(必要に応じて複数立ち上げたりcronも入れたりする)
- deployコマンド(バージョニングや)
などがあります。いずれも記述量は少ないものの、たまに気をつけることがあるのでshell化しています。詳しくはサンプルを見てください。
なぜこうなったのか
vendorについて
前述したとおり、GAEにはvendorの考慮がされていないようで、普通にvendor以下に置いてしまうとデプロイがうまくいかなかったりが頻発しました。
goapp
コマンドを使ったり nobuild_files
の記述で回避できているケースもあるようですが、面倒なのでフォルダを別で管理してGOPATHに追加することで誤魔化しています。
また、GCPUGで聞いた所、 appengine
パッケージでなく、 google.golang.org/appengine
を使うことが推奨されているようなので、glideなどで管理しつつなるべく最新に追従させるようにしています。
(今後go1.8が正式対応するにあたり、context周りで破壊的変更が入るだろうとのことでした。)
appディレクトリについて
GAEへのデプロイをする際に、普通にsrc以下にエントリのファイルを置くと、ビルド時になぜかファイルが重複してアップロードされるようでエラーになります。
エントリポイントとその他ファイルを別ディレクトリに置くと上記問題が解消されるとの記事を見かけたので、そのように対応しています。
app.yaml(local.yaml / prod.yaml)について
GAEでは、各種設定をyamlファイルで記述することになっています。
デフォルトではapp.yamlが読まれるのですが、環境毎に設定を分けたい場合は任意のファイル名にできます。
例えば、localでは外部サーバーへのアクセスはしてほしくない、ログをたくさん吐きたい、という場合のために、各環境毎に環境変数を変えたyamlを用意しています。
また、複数のGAEアプリケーションを立ち上げることはよくあると思うので、service名を付けて区別するようにします。
GAEへのデプロイ
gcloudではデフォルトでは日時でバージョンが振られます。
これだけではどの状態のアプリをリリースしたのかわからないので、git hashをversionに含めるようにしています。
testやlintについて
特に気にせず書けています。
goのappengineのコードでのテストの書き方はまた別の機会に書きます。