golangのWAFのechoで書いたAPIをGAE (Google App Engine) へデプロイする方法

golangのechoで書いたAPIをGAEへデプロイする際に詰まったのでメモ。

 GAE (Google App Engine) は、APIサーバなどをフルマネージドな環境に手軽にデプロイすることができる優れたサービスですが、golangの仕様上、デプロイの方法がわかりにくくなっていたのでメモ。

 フルマネージド:完全運用保守管理代行サービス。googleがサーバが落ちないようにメンテナンスしてくれるってこと。

 ポイント1:GOPATH配下のディレクトリで作業する

通常、~/go/src/github.com/{user_name}/{project_name}に設定されているgopath配下で作業する。

これはgolangでコーディングをするならimportの仕様上不可避かと思います。

  • golangでは import "github.com/{user_name}/{project_name}/test"のようにプロジェクト配下のサブディレクトリを読み込んだ場合、GOPATHに設置してあるファイルが優先的に参照されてしまうため、ホームディレクトリなどにプロジェクトを設置していると、更新したファイルが反映されない!みたいになる

 ポイント2;vendorディレクトリにすべての依存関係を格納する

GAEでは、golangのすべてのソースコードと依存関係をアップロードしてソフトウェアがビルドされます。ここで問題になるのが、ローカルのプロジェクトと同様にGAE上でも依存関係が解決できるようにしてあげること、です。これが結構めんどくさいです。

なぜならばGAEでは、vendorツール(依存関係をプロジェクト配下の/vendorディレクトリにまとめるツール)が利用できないからです。

通常、ローカルでgolangのプログラムを実行する際には、/vendorディレクトリと$GOPATH配下の2つを参照して依存関係は解決されるのですが、GAE上にdeployする際には$GOPATHのみが参照されます。すべての依存関係を$GOPATH配下に格納した状態でdeployコマンドを叩かないとエラーで死にます。クソめんどくさい仕様にしてんじゃねーよ。という心の声をぐっとこらえて以下のような対策を行いましょう。

  • プロジェクト内部にgopathディレクトリを作成して、そこにすべての依存関係が集まるようにシンボリックリンクを張る
  • デプロイコマンドを叩くタイミングで上記のgopathディレクトリが環境変数の$GOPATHに設定されているようにする (direnvというツールを使う)

具体亭には次のようなディレクトリ構成がおすすめです。

.
├── Gopkg.lock
├── Gopkg.toml
├── README.md
├── app
│   └── (プロジェクトのメインのソースコード)
├── gae
│   ├── .envrc (gaeにデプロイする際に$GOPATH=goathになるようにするための設定ファイル)
│   ├── app.go
│   └── app.yaml
├── gopath
│   └── src -> ../vendor (vendorディレクトリへのsymリンク)
├── main.go (gaeに依存しない実行ファイル)
└── vendor
    ├── github.com ── {project_name} -> ../../../app (appディレクトリへのsymリンク) 
    └── (depなどのツールで管理されるその他の依存関係)

main.goを実行する際には通常のvendorディレクトリとGOPATH配下のappディレクトリから依存関係が解決され、 GAEへデプロイする際 (gaeフォルダないでgcloud app deployコマンドを叩く際)には gopath配下のsymリンクからすべての依存関係が解決されます。

具体的なソースコードは下記にあります。

github.com