#本記事について
Golang+ginでローカルで作ったWebアプリをGoogleAppEngineに載せる時にいろいろハマったのでその注意点をまとめます。
メモ書きです。
#Golang+ginでローカルで作ったWebアプリ
ユーザの要求に合わせてデータベースからデータを引っ張ってきて表示するよくあるWebサイトです。
https://github.com/notvitor/go-gin-boilerplate
の上に、DB接続やらHTTPリクエストの処理やらセッション管理をするGolangコードを別ファイルに作って参照しています。
MyProject以下に
server.go
app.yaml
dbフォルダ(CloudSQLを操作するためのGoソースが入ってる)
sessionフォルダ(セッション管理をするためのGoソースが入ってる)
requestフォルダ(HTTPリクエストを処理するためのGoソースが入ってる)
templatesフォルダ(HTMLがいっぱい入ってる)
publicフォルダ(jsが入ってる)
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/contrib/sessions"
"MyProject/request"
"MyProject/db"
"MyProject/session"
"fmt"
"strconv"
)
Go+ginで作ったWebアプリをデプロイする記事は大抵Golangソース単体をデプロイする簡単なものだけだったのでGolangソースが複数あるものについて言及していきたいと思います。
#デプロイする時のPermissionエラー
goapp deploy プロジェクトフォルダ
を最初使っていましたが、
[Google App Engine]You do not have permission to modify this app
というエラーが出てだいぶ困りました。そんな時以下のサイトを見つけました。
同じソースコードをapp.yamlのapplication: だけ変更して違うアプリケーションIDのところへデプロイしようとした時によく出ます。これ実はappcfg.pyがcookieを利用して前回入力したアカウントを記憶しているので、cookieに保存されているアプリケーションIDとapp.yamlに記述されたアプリケーションIDが異なっていることが原因です。
なので、このエラーが出たらアカウントが違うかCookieに違うものが保存されているのか、その両方かも。
ということで、アカウントが正しいことを確認した後
appcfg.py -A [GAEに作ったプロジェクトのID] -V v1 update --no_cookies [デプロイしたいファイル群のディレクトリパス]
を叩いてデプロイしたほうが、Cookieがどうのこうのに煩わされることがないと思います。
Failed parsing input: app file hoge.go conflicts with same file imported from GOPATH
これの解決策を見つけるのも大変でした。
appengineによるimportと、そこでimportされたソースコードによるimport(自分のケースだとmain.goがimportしてる)が、同じファイルをimportしようとしているっぽい。
ということですね。
僕もこのエラーが出た時に$GOPATH以下のProjectに対してデプロイしようとしてました。
(まぁローカルで動作確認したものをデプロイするわけだし、何も知らないと必ず1回はこのエラーに出くわすと思う)
##解決策:
プロジェクト自体をコピーしてそのフォルダに対してappcfg.pyでデプロイしました。
$GOPATH/src/以下に作ってあったプロジェクトフォルダをコピーして、~/temp/以下に置いて
appcfg.py -A [GAEに作ったプロジェクトのID] -V v1 update --no_cookies ~/temp/MyProject
みたいな感じですね。
ただ、これだいぶクセがあって、デプロイ結果には
~temp/MyProjectの:
server.go、app.yaml、HTMLテンプレート、JSファイル
$GOPATH/src/MyProjectの
server.goで参照したgoファイル
というようにファイルの種類によってデプロイされるもののパスが違ってきます。
これは気をつけたほうがよいですね。
appengineによるimportがされてるから仕方ないのかなと自分を無理やり納得させていますが、中々気づけませんでした。
#GAEにデプロイする前に
goapp serve [プロジェクトディレクトリ]
でやってみてもしローカル上で動くようなら、デプロイの仕方を間違えなければGAEでも動くと思います。
(ソースはなくて、経験則です。)
#CloudSQLをdbrで、GAEで使うときに注意すること
世間ではdbrを使ってCloudSQLを叩く人があまりいなくてちょっと苦労しました。
CloudSQLの設定
Google Cloud SQL初期設定
http://java.sakura.ne.jp/base/page-287
Google Cloud SQL外部からの接続設定 アクセス許可
http://java.sakura.ne.jp/base/page-302
dbrに関しては↓を見ると良いと思います。
dbr – Go 言語 O/R Mapper の紹介
https://eurie.co.jp/blog/engineering/2015/12/go-lang-ormapper-dbr
##ローカルのMySQLサーバにアクセスする時
masterConnection, _ = dbr.Open("mysql", "root:@tcp(127.0.0.1:3306)/DBName", nil)
masterDBSession = masterConnection.NewSession(nil)
でDBに接続するセッションができます。(MySQLサーバは既に立っている前提です。)
これを使って普段は
var u DBUsers
sess.Select("*").From("users").Where("id = ?", id).Load(&u)
という感じのコードでMySQLからデータを取ってくるなどします。
##(非推奨)CloudSQLにIPアドレス直書きでアクセス
conn, _ = dbr.Open("mysql", "ユーザ名:パスワード@tcp(IPv4アドレス/DBName", nil)
sess = conn.NewSession(nil)
何故非推奨なのかというと、IPアドレス経由でアクセスするとものすごく遅いからです。
普通のアプリとしては使い物にならないレベルですが、適当にダミーデータなどを入れておきたいなと思った時にはこの方法で少しInsertしたりUpdateしたりはしました。
それとローカルからgo+dbrでCloudSQLにアクセスするにはこうするしかないきがするのでローカルでCloudSQLの動作を見たいならこれを使いましょう。
参考:http://otiai10.hatenablog.com/entry/2016/04/03/054116
本番は動くがローカルで動かない。なぜなら、ローカルのDev Serverには環境変数を直接渡せないようだ。
##GAE上からCloudSQLにアクセス
dbr.Open("mysql","root@cloudsql(プロジェクト名:インスタンス名)/(DB名)",nil)
sess = conn.NewSession(nil);
GAEにデプロイしたらこの方法を取る。IPアドレスでアクセスしてた時が嘘のように早く動く。
ただこの記法はGAEにデプロイしたWebアプリからアクセスする時用なので、ローカルでこれを動かしてもCloudSQLにアクセスはできません。