【go + gin + gorm】GAEとCloud SQL for MySQLを使ってデプロイしてみる


[【Go+Gin+Gorm】初心者だから超簡単webサービス作ってみる](https://qiita.com/dai-maru/items/7e97fc6623375c7eb14a)
[【go + gin + gorm】webアプリにログイン機能を追加してみる](https://qiita.com/dai-maru/items/f7cdd22baf3425a1722d)
続きです。

今回は、劣化版ツイッターアプリをGCPを使ってデプロイしてみるという内容です。
GCPで使うのは、`GAE standard環境`と、`Cloud SQL for MySQL`です。
コードは[github](https://github.com/ymdd1/mytweet-deploy)に上げています。

# `go modules`を使う
今回、GAEにデプロイするにあたって、`$GOPATH`周りでエラーが起こったので、`go modules`を使うことにしました。
`go modules`は依存モジュール管理ツールです。
Go では`GOPATH`という概念があって、Go のコードは外部ライブラリも含めてすべて`$GOPATH/src` 以下に置くことになっています。
つまり、外部ライブラリと自分のコードが同列の場所にあるということになります。
でもそれだとプロジェクトごとに違うバージョンのライブラリを使いたい時などは困る。開発する度にいちいち外部ライブラリを消して入れ直したりをしなくてはならない。
詳しくは以下のリンク先を読むといいかもしれません。
[Go Modules](https://qiita.com/propella/items/e49bccc88f3cc2407745)
[Go言語の依存モジュール管理ツール Modules の使い方](https://blog.mmmcorp.co.jp/blog/2019/10/10/go-mod/)

以下のコマンドを実行していきましょう。

```shell

$ cd <このプロジェクト名>
// 依存モジュールの情報は `go.mod` と `go.sum` という名前のファイルに記載される。
$ go mod init
// 依存モジュールの自動インストール
$ go build

```
ちなみに、自作パッケージをimport文に記載するときは、
`<プロジェクトのディレクトリ名>/<自作パッケージディレクトリ名>`
にしないと`go build`のときにエラーになりました。

```go:main.go
// 今回の場合はこんな感じ
mytweet-deploy/crypto
```

# GAEへのデプロイ
goで作られたプログラムがデプロイされる際にGAE上で行われていることは、アプリケーションのビルドに必要なソースコードを `$GOPATH` 含めて探索し、すべてアップロードした上でリモートでコンパイルするという流れ。
手元でコンパイルしたアプリケーションのバイナリをアップロードするのではないし、主要なソースコードだけをアップロードしてリモートで `go get` するわけでもないようです。
この辺りは以下のブログで言及されていました。
[Google App EngineでGoを動かすときに知っておくべきこと（ソースコード・ビルド編）](https://motemen.hatenablog.com/entry/2016/11/gae-go-building)


ここからは`gcloud`コマンドがローカルで使えるようになっていることを前提に話を進めます。
GCP上でプロジェクトを作成してください。
`app.yaml`ファイルがある階層に`cd`して以下を実行。

```
$ gcloud app deploy
```
GAEに他のインスタンスがない場合は、GAEのインスタンス名はdefaultでいいですか？
GAEにdefaultという名前のインスタンスがある場合は、GAEのインスタンス名は何にしますか？
などを聞かれると思うので、入力してください。
何を入力したか忘れてもあとでブラウザ上で確認できます。

そのあと`Y/n`という究極の選択を迫られるので、すかさず`Y`。
数分かかるので、コーヒーでも飲んで休憩してください。
特にエラーが出なければ、ターミナルで以下を実行。

```
$ gcloud app browse
```
ブラウザが現れてお馴染みのハローワールドが出てればOK。

嘘です。
エラーが出てたらOKです。
GCPコンソールの`App Engine`上にさっき作ったインスタンス名が存在していればOKです。
エラーが出ているのは、データベースに接続できないからです。
これからCloud SQLにインスタンスを作って、アプリ側からデータベースに接続できるように設定していきます。
つまり、ここまででアプリのデプロイは完了したってことですね。

どんなエラーが出てるか見たいねんって方は、以下を実行。

```
$ gcloud app logs tail -s <インスタンス名>
```
おそらくデータベース接続の部分でエラーが出ているはず。。

# 本番環境とローカル環境との共存
本番環境のMySQLにつなぐ部分と、ローカル環境のMySQLにつなぐ処理は以下のように記述しました。
`appengine`ライブラリの`IsAppEngine()`関数で、App EngineアプリがApp Engineで実行されているかどうかをbool型で取得することができます。
これでローカルでもGAE上でも動かすことができます。

```go:main.go
    if appengine.IsAppEngine() {
		db, err = gorm.Open("mysql", cloudSQLConnection)
	} else {
		db, err = gorm.Open("mysql", localConnection)
	}
	if err != nil {
		panic(err.Error())
	}
```

`appengine`ライブラリの[公式リファレンス](https://godoc.org/google.golang.org/appengine#IsAppEngine)

# Cloud SQLにデータベースを作成する。
先ほど言ったように、ただ単にGAEにプログラムをデプロイしてもデータベースがないと今回のプログラムは動きません。
まずは以下のリンクからGoogle Cloud SQL APIを有効にして下さい。
https://cloud.google.com/sql/docs/mysql/admin-api/?hl=ja

ブラウザでGCPのコンソールを開いてください。
左上のハンバーガーメニューから`SQL`をクリック。
`インスタンスを作成`をクリック。
`MySQL`をクリック。
項目を適当に埋めていきます。
`作成`をクリック。
作成されたインスタンスをクリックすると概要というページに飛びます。
左メニューから`接続`をクリック。
`プライベートIP`にチェックを入れて、`関連付けられたネットワーキング`には、先ほどGAEで作ったインスタンス名を選択して下さい。その後`保存`をクリック。
次は左メニューから`ユーザー`をクリック。ここではデータベースにアクセスできるユーザーを作成します。
`ユーザーアカウントを作成`をクリック。ユーザー名、パスワードを入力して下さい。保存しましょう。どこかにメモして下さい。
最後に、左メニューから`データベース`をクリック。ここではデータベースを作っておきます。
`データベースを作成`をクリックして、名前を付けて保存。文字コードはutf8です。

設定は以上です。
`概要`ページに戻って、`このインスタンスに接続`という欄の`インスタンス接続名`をどこかにメモして下さい。
設定を`.env`に記入していきます。

```.env
// インスタンス接続名
mytweet_CONNECTIONNAME=project-id:region-name:instance-name
// 作成したユーザー名とパスワード
mytweet_USER=username
mytweet_PASS=12345678
// 作成したデータベースの名前
mytweet_DBNAME=test

```

保存をしたら、先ほどのようにGAEにデプロイして下さい。

```
$ gcloud app deploy
$ gcloud app browse
```

エラーなく画面が表示されたらデプロイ完了です。
お疲れ様でした。
ユーザー登録してみたり、ログインしてみたりして下さい。

# Cloud SQLの中身をローカルで確認する
Cloud SQL Proxy を使用して、ローカルからCloud SQLに接続します。
以下MacOS 64ビットの方用です。それ以外の方は[ローカルマシンに Cloud SQL Proxy クライアントをインストールする](https://cloud.google.com/sql/docs/mysql/quickstart-proxy-test?hl=ja#install-proxy)を参照ください。

```

// プロキシをダウンロードします。
$ curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64

// プロキシを実行できるようにします。
$ chmod +x cloud_sql_proxy

// さっきメモしたインスタンス接続名が必要です。
$ ./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:3306

// MySQLを起動します。さっき作ったユーザー名が必要です。
$ mysql -u <USERNAME> -p --host 127.0.0.1 --port 3306
```

これでCloud SQL上のMySQLを確認することができます。
select文でテーブルの中身を確認したりしてみて下さい。

こちらがCloud SQL Proxyを導入する際の公式ドキュメントです。
[ローカルテストにプロキシを使用する場合のクイックスタート](https://cloud.google.com/sql/docs/mysql/quickstart-proxy-test?hl=ja)

# 最後に
次はセッションをやろうかなと思ってます。