RailsアプリをGAEにデプロイしCloudSQL, CloudStorageと連携させる

最近、GCPの注目度が高まってきていると感じています。

機能が多いAWSよりもより手軽にできるという点やkubernetesの恩恵を受けやすいのが魅力的だと思います。さらに、個人的に今後開発にGo言語を使う新規プロジェクトが増えいくと思っていて、その際にGoogle発のものは相性よさそうだなーとぼんやり思ったりしています。

インフラを本格的に運用した経験はありませんが、簡単にRailsアプリをGAE(Google App Engine)にデプロイしてみたのでその方法をメモしておこうと思います。

GCP内にプロジェクトを作成し、gcloudをインストールしてある状態であることが前提です。

GCPの[公式ドキュメント](https://cloud.google.com/docs/?hl=ja)をよめば問題なくデプロイできるので、注意点や重要なポイントのみを中心に記していきます。

# App Engineにデプロイ

デプロイしたいアプリのディレクトリ直下にapp.yamlを用意します。

```ruby:app.yaml
runtime: ruby
env: flex
entrypoint: bundle exec rackup --port $PORT
```

そして、デプロイしたいアプリとGCPとの連携が終わっていれば、こちらのコマンドを打つだけでApp Engineにデプロイができます。

```shell-session
$ gcloud app deploy
```

## 環境変数をセットしたい

環境変数があるプロジェクトがほとんどだと思います。
app.yamlに環境変数を書くことでGAEに環境変数を渡せます。

```ruby:app.yaml
runtime: ruby
env: flex
entrypoint: bundle exec rackup --port $PORT
env_variables:
  SECRET_KEY_BASE: [YOUR_SECRET_KEY_BASE]
```

また、app.yamlはgit管理したいけど、環境変数はgit管理したくない場合はyamlファイルをもう一つ用意し、app.yamlによみこませ、そのyamlファイルをgitignoreさせればいいかと思います。

```ruby:app.yaml
runtime: ruby
env: flex
entrypoint: bundle exec rackup --port $PORT
includes:
- secret.yaml
```

```secret.yaml
env_variables:
  SECRET_KEY_BASE: [YOUR_SECRET_KEY_BASE]
```

```git:.gitignore
secret.yaml
```

## ログがみたい
ログがみたい場合は2つ方法があります。

1. ターミナル上で`gcloud app logs read`を打ってログをみる方法
2. GCP上のログビューワーでログをみる方法


## すでにDockerfileが存在する
GAEにデプロイしたアプリはDocker上で動くためDockerfileがプロジェクト直下にあるとRuby runtimeでデプロイができません。その場合はCustom runtimeでのデプロイになります。

```ruby:app.yaml
runtime: custom
env: flex
entrypoint: bundle exec rackup --port $PORT
```

もしRuby runtimeでデプロイしたい場合は、DockerfileをDockerfile-devなどに置き換えておくといいかもしれません。

## デプロイに使用するDockerfileが知りたい

[こちら](https://github.com/GoogleCloudPlatform/ruby-docker/tree/master/ruby-base)にGCPで使用されるRubyのbase imageが確認できます。

このbase imageを用いて新しいDockerfileを作ることもできます。

```Dockerfile:Dockerfile
FROM l.gcr.io/google/ruby:latest
```


# CloudSQLと連携させる

今回はGCP上でMySQLでインスタンスを作成し、アクセスに使うユーザーやデータベースを作成します。

まず、database.ymlを変更します。

```ruby:database.yml
production:
  <<: *default
  database: [YOUR_DATABASE]
  username: [YOUR_USERNAME]
  password: [YOUR_PASSWORD]
  socket: /cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]
```
`[YOUR_INSTANCE_CONNECTION_NAME]`はGCP上で確認できますが、作成したプロジェクトの名前がわかれば以下のコマンドでもわかります。

```shell-session
$ gcloud sql instances describe [YOUR_PROJECT_NAME]
```

また、app.yamlは以下のように変更します。

```ruby:app.yaml
runtime: ruby
env: flex
entrypoint: bundle exec rackup --port $PORT
beta_settings:
  cloud_sql_instances: [YOUR_INSTANCE_CONNECTION_NAME]
includes:
- secret.yaml
```

APIを有効にするのも忘れずに行いましょう。APIを有効にしないと、Google::Cloud::PermissionDeniedErrorが発生します。

## migrationを実行する

CloudSQL上でのmigrationの実行は`gem 'appengine'`にて行えます。

```shell-session
$ bundle exec rails appengine:exec -- bundle exec rails db:migrate
```

ちなみに、ridgepoleでもきちんとmigrationできました。

```shell-session
$ bundle exec rails appengine:exec -- bundle exec ridgepole -c config/database.yml -E production --apply -f db/schemas/Schemafile
```
## MySQLのオプションを追加したい

データベースの文字コードをいじった時などに、オプションを設定したい時があるかと思います。
そういったときは、Cloud SQLフラグを使用するとMySQLのパラメータやオプションの指定内容を変更できます。

# CloudStorageと連携させる

carrierwave, fogを使ってCloudStorageと連携させます。アクセスキーとシークレットキーを取得後、initialize以下にcarrierwave.rbを作成します。

```ruby:carrierwave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'Google',
    google_storage_access_key_id: [YOUR_ACCESS_KEY],
    google_storage_secret_access_key: [YOUR_SECRET_ACCESS_KEY]
  }
  config.fog_directory = [YOUR_BUCKET_NAME]
end
```

あとは、uploader用のファイルに`storage :fog`を追加すれば完了です。

# 終わりに

デプロイ時に少しエラーがでたりしましたが、意外とすんなりできました。

個人で開発したWebサービスなどでインフラを任せてしまいたい時に積極的に使っていけたらなと思っています。