Rails×React×MySQLなSPAをHerokuにデプロイする手順

f:id:Ushinji:20180721102518p:plain

HerokuはRailsアプリをデプロイする際には簡単にデプロイすることができるのですが、フロントがAssetPiplineではなく、webpackを使っていたりすると設定が追加で必要になったりします。

最近まで個人的に作成したRails×ReactなSPAをデプロイするまで試行錯誤したので、その手順をアウトプットしたいと思います。

対象のアプリケーション

今回の対象はRails×ReactなSPAです。簡単なKPTを残せるWebアプリケーションです。 リポジトリは以下を参照ください。

github.com

ちなみに、バックエンドはRESTfulなAPIではなく、単一のエンドポイントからなるGraphQLを使っていたり、フロントがReduxを実装しているが使わず、ApolloClientでフロントのデータの管理をしていたりします。

本来はGraphQL, ApolloClinetの勉強目的で開発を始めたので、こちらについてもアウトプット記事を書きたいと思っています(願望)

herokuへのデプロイ手順

herokuへログイン

ますコンソール上からHerokuへログインします。アカウントがない方はアカウントを作成してください。 heroku

$ heroku login

herokuアプリケーションの作成

以下のコマンドからherokuへデプロイするアプリケーションの置き場を作成します。

$ heroku create YOUR_APP_NAME

create以下には作成するアプリケーションの名前を指定します。ここで指定した名前がURLに付与されます。例えば上述のコマンドの場合、https://YOUR_APP_NAME.herokuapp.com/となります。一方で、アプリ名を指定しない場合はランダムな値が指定されます。

HerokuへMySQLアドオンを追加

Herokuの標準のDBはPostgresです。そのため、MySQL使う場合はアドオンの追加が必要になります。MySQLのアドオンは自分の知る限りClearDBJawsDBの二種類あります。それぞれの違いはMySQLバージョンの違いです。

  • ClearDB の MySQL のバージョンは 5.5系
  • JawsDB の MySQL のバージョンは 5.7系

(参照:Heroku (Rails) で MySQL 使う。)

今回はMySQLバージョンが5.7系のJawsDBを使用しました。理由として、timestampカラムでマイクロ秒まで保存する形式にしたのですが、それがMySQL5.5系で対応して居なかったからです。

実際のアドオンのインストールコマンドは以下の通り。

$ heroku addons:create jawsdb:kitefin

また確認コマンドは以下の通り。

$ heroku addons

Add-on                              Plan     Price  State
──────────────────────────────────  ───────  ─────  ───────
jawsdb (jawsdb-asymmetrical-31409)  kitefin  free   created
 └─ as JAWSDB

Heroku上のDBとRailsアプリの連携

先ほど導入したHeroku上のDBとRailsアプリケーションの連携のための設定をします。

まずRails側でDB連携で必要な情報の設定を行います。設定についてはconfig/database.ymlに行います。設定内容は以下の通りです。今回のDB情報(というかパスワード)はファイル直書きはセキュリティ的にダメなので、環境変数から読み込むようにしています。

// config/database.yml

production:
  <<: *default
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  url: <%= ENV['DATABASE_URL'] %>

次に、Heroku上のDBの設定を確認を行います。確認は以下のコマンドから実行できます。

$ heroku config | grep JAWSDB_URL

JAWSDB_URL:               mysql://<DATABASE_USERNAME>:<DATABASE_PASSWORD>@<HOST>/<DATABASE_NAME>

JAWSDB_URLの値の各要素にRailsと連携するための情報が含まれています。これらの情報をheroku上の環境変数へ設定します。設定コマンドはheroku config:setです。今回の設定では以下の設定を行いました。

$ heroku config:set DATABASE_NAME="<DATABASE_NAME>"
$ heroku config:set DATABASE_USERNAME ="<DATABASE_USERNAME>"
$ heroku config:set DATABASE_USERNAME ="<DATABASE_PASSWORD>"
$ heroku config:set DATABASE_URL ="<JAWSDB_URLの値をそのまま設定>"

最後にherokuのDBのadapterの値を変更します。RailsアプリはDBのadaptermysql2なので、変更します。adapterはDBのURLの先頭記載されています。

$ heroku config:set JAWSDB_URL="mysql2://~~(以下変更なし)~~~"
$ heroku config:set DATABASE_USERNAME="mysql2://~~(以下変更なし)~~~"

以上でDBとRailsの連携は完了です。

Procfileの作成

Procfileはデプロイするアプリがどのプロセスを利用するか宣言するファイルです。 (参考:HerokuのProcfileの役割)

今回作成したファイルは以下の通り。webというプロセスに、Railsアプリを起動するという宣言。

web: bundle exec rails server -p $PORT

Webpackビルドの設定

herokuデプロイ中にwebpackビルドを実行する設定を追加します。

まず、以下が今回のアプリのwebpackビルドのscriptsです。

// package.json
"scripts": {
  "start": "webpack-dev-server --mode development --output '[name].js'",
  "clean": "rimraf public/dist",
  "build:production": "cross-env NODE_ENV=production webpack --mode production",
  "build": "npm-run-all clean build:production",
  "heroku-postbuild": "npm-run-all clean build:production" // <-heroku用に追加
},

その中でheroku-postbuildがheroku用に追加したscriptになります。heroku-postbuildはherokuのデプロイ後に実行される処理を指定できるscriptなので、ここに本番環境用のwebpackビルドコマンドを記載すればOKです。

Herokuへアプリケーションへデプロイ

実際にアプリケーションをHeroku上へデプロイします。デプロイコマンドは以下の通り。masterブランチをherokuへプッシュすれば自動デプロイされる簡単。

$ git push heroku master

DBのMigration

デプロイに成功したら、DBのMigrationを行います。コマンドは以下の通りです。

$ heroku run rake db:migrate

アプリの表示

以下のコマンドでアプリをブラウザで表示できます。

$ heroku open

詰まったポイント

Migrationでシンタックスエラー

問題

Heroku上でDB Migrationしたら以下のシンタックスエラーで失敗する事が起きました。

Caused by:
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the rightsyntax to use near '(6) NOT NULL, `updated_at` datetime(6) NOT NULL) ENGINE=InnoDB ROW_FORMAT=DYNAMI' at line 1

原因・解決方法

原因はMySQLバージョンが合っていなかった事です。最初はClearDBを使っていたのですがこれがMySQL5.5系であり、これでdatetime(6)(マイクロ秒)に対応していなかった事が原因でした。なので、解決策としては、MySQL5.7系のJAWSDBへ設定しなおせば問題なくMigrationできました。

503 / Application Error

問題

次の問題は、デプロイ完了したけど以下の画面が出てアプリが表示できなかった問題。

スクリーンショット 2018-07-21 9.54.50.png

ログを見ても以下のエラーだけで原因がわからず。

at=error code=H10 desc="App crashed" method=GET path="/" host=myapp.herokuapp.com fwd=17.17.17.17 dyno= connect= service= status=503 bytes=

原因

ちゃんとデプロイができてなさそうなので、git push heroku masterしてからのデプロイの動きをターミナルで眺めていたら、なぜからデプロイ中なのにrails serverが実行されるところで、rails newコマンドが実行されていました。ここに問題の原因がありそうです。

意図せずrails newが実行される原因をググっていたところ、今回の根本の原因は./binディレクトリがherokuへプッシュされていなかった事が原因でした。そもそもrails serverrails consoleといったコマンドは、rails newした時に作成される./bin/ディレクトリ以下のスクリプトファイルがあるから実行できるコマンドです。そのため、それらのスクリプトファイルがない場合にrails serverなどのrailsコマンドを実行すると問答無用でrails newと判断されてしまっていたということです。

解決方法

原因がわかった事で、解決方法は.gitignoreから./bin/を記載を削除する事です。これで./bin/ディレクトリもプッシュされます。

終わりに

herokuはrailsオンリーなアプリなら爆速でデプロイできるのですが、MySQL使ったり、webapck使ったりすると色々設定が増えていく印象です。それでも自分でAWSのEC2立ち上げるよりもクソ簡単にデプロイので簡単なアプリ開発では重宝されます。

参考

初心者向け!HerokuでRailsアプリを公開する方法 | TechAcademyマガジン HerokuにRails + React + webpackのプロジェクトをデプロイする | ichimaruni-design