【サービスを公開する方法を学ぼう!】Herokuでのデプロイを解説！

今回はHerokuを用い、サービスを公開する方法を発信していきます。
まず、ネットワークを通じてWebアプリケーションなどのシステムを公開し、利用可能な状態にすることを`デプロイ`と言います。サーバーを借りてデプロイを行う作業は手間がかかります。その手間を大幅に減らしてくれるのが、`Heroku`というサービスです。Herokuは基本機能だけであれば無料で使用でき、デプロイの手間が少なく容易であるというメリットがあります。では、ここからはHerokuを使ってサービスをデプロイする方法を解説します！


#はじめてデプロイをする場合

初めてデプロイをする場合、手順は大きく分けて8つあります。

1. Herokuにアカウント登録する
2. Heroku CLIをインストールする
3. Heroku上にアプリケーションを作成する
4. DBを使用できるように設定する
5. master.keyを環境変数として設定する
6. Herokuへアプリケーションの情報をpushする
7. Heroku上でマイグレーションを実行する

ここからは以下の手順を1つずつ解説していきます。

## 1.Herokuにアカウントを登録する
まずは、Herokuでデプロイできるように公式サイトに行きアカウントを登録します。下記のリンクからHerokuの公式サイトへ行けるので登録しましょう。
[Heroku](https://signup.heroku.com/login)


## 2.Heroku CLIをインストールする
HerokuのCLIをインストールします。CLIをインストールすると、`heroku`というコマンドが使用できるようになり、ターミナルからHerokuへアクセスが可能になります。それでは、ターミナルを開き下記のコマンドを入力してください。


```ruby:ターミナル
% brew tap heroku/brew && brew install heroku
```

インストールが終了したら、完了を確認するために下記のコマンドを入力しましょう。

```ruby:ターミナル
% heroku --version
  heroku/7.40.0 darwin-x64 node-v12.16.2
```
上記のようにバージョンが出力されれば成功です。（バージョンの値は実際の表示と異なる場合があります）

## 3.Herokuにログインする
次に、ターミナルからHerokuへログインします。下記のコードを入力し、メールアドレスやパスワードを入力していきましょう。

```ruby:ターミナル
# Herokuへログインするためのコマンド
% heroku login --interactive
  => Enter your Heroku credentials.
# メールアドレスを入力し、エンターキーを押す
  => Email:
# パスワードを入力して、エンターキーを押す
  => Password:
```
下記の画像のようになっていればログインできました。

![](https://i.gyazo.com/61c6e599cbff0d01f2c8aa5f47ed0cab.png)


## 4.Heroku上にアプリケーションを作成する
以下のコマンドを順に実行し、アプリケーションの作成と、実際に作成されているかの確認を行います。


```ruby:ターミナル
% heroku create アプリケーション名
```
下記のコマンドを入力し、正しく設定できたことを確認してください。

```ruby:ターミナル
% git config --list | grep heroku
```

`fatal: not in a git directory`以外が表示されていれば、このまま進んでください。

# 5.DBを使用できるように設定する

DBが絡むものはここでDBの設定をします。今回は、DBにMySQLを使用するための設定を行います。`ClearDBアドオン`を追加することによって設定できます。`ClearDBアドオン`とはMySQLを使うためのツールです。これを追加することにより、HerokuでMySQLを使用できるようになります。それでは、下記のコマンドを入力して、`ClearDBアドオン`を追加しましょう。

```ruby:ターミナル
% heroku addons:add cleardb
Creating cleardb on ⬢ ajax-app-123456... free
Created cleardb-vertical-00000 as CLEARDB_DATABASE_URL
Use heroku addons:docs cleardb to view documentation
```
上記のように出力されれば成功です。

これでデータベースをMySQLに設定できました。しかし、Ruby on Railsを使う場合は、MySQLに対応するGemについて考慮する必要があり、そちらの設定を変更します。

まず、下記のコマンドを入力してください。

```ruby:ターミナル
% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`
```

これでClearDBデータベースのURLを変数heroku_cleardbに格納できました。

続いて、下記のコマンドを入力してください。

```ruby:ターミナル
% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}
以下、コマンドの実行結果
Setting DATABASE_URL and restarting ⬢ ajax-app-123456... done, v◯◯
DATABASE_URL: mysql2://000000000000:0aa0000@us-cdbr-east-02.cleardb.com/heroku_aaa00000000?reconnect=true
```

これでデータベースのURLを再設定できました。

# 6. master.keyを環境変数として設定する
OSが提供するデータ共有機能の1つで、「どのディレクトリ・ファイルからでも参照できる変数」を設けることができます。一般的な用途の1つとして、`「外部に漏らしたくない情報を環境変数にセットする」`というものがあります。その環境変数を設定するためには、`heroku config`というコマンドを使用します。
Heroku上に環境変数を設定します。下記のコマンドを入力してください。

```ruby:ターミナル
% heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
```
 Heroku上で環境変数を確認しましょう
設定が正しくできているか、Herokuの環境変数一覧を表示してみましょう。下記のコマンドを入力してください。

```ruby:ターミナル
% heroku config
```

ターミナル上に`RAILS_MASTER_KEY`という変数名で値が設定されていれば成功です。


# 7.Herokuへアプリケーションの情報をpushする
デプロイをする前に、Herokuで利用する環境を指定しましょう。Herokuには、`Stack（スタック）`という環境が用意されています。`Stack`とは、Herokuにおけるアプリケーションの動作環境のことです。`Stack`はデプロイされたアプリケーションを読み取り正常に稼働させるために用意されています。それでは、下記のコマンドを実行しましょう。

```ruby:ターミナル
% heroku stack:set heroku-18 -a アプリケーション名
```

Stackの設定が終わったら、実際にデプロイしていきます。Herokuにデプロイする際には、Gitの仕組みを使用するのでした。Gitで管理しているリポジトリをHerokuへ反映することで、Heroku上で該当するアプリケーションの操作が可能になります。Gitで管理しているリポジトリをHerokuに反映するためには`git push heroku master`というコマンドを用います。下記のコマンドを入力し、Herokuへアプリケーションの情報をpushしましょう。

```ruby:ターミナル
% git push heroku master
```

# 8. Heroku上でマイグレーションを実行する
Herokuにアプリケーションの情報を反映することができました。しかし、データベースにはマイグレーションの情報が反映されていません。そこで、Heroku上で実行したいコマンドに用います。rails db:migrateであれば`heroku run rails db:migrate`と実行します。そうすることによって、Heroku上でコマンドが実行できます。下記のように、`heroku run`を頭につけて、マイグレーションを実行してください。

```ruby:ターミナル
% heroku run rails db:migrate
Running rails db:migrate on ⬢ ajax-app-123456... up, run.8920 (Free)
D, [2020-05-08T08:22:50.410454 #4] DEBUG -- :    (2.9ms)  SET NAMES utf8mb4,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
D, [2020-05-08T08:22:50.467023 #4] DEBUG -- :    (2.6ms)  SELECT @@innodb_file_per_table = 1 AND @@innodb_file_format = 'Barracuda'
D, [2020-05-08T08:22:50.479166 #4] DEBUG -- :    (11.6ms)  CREATE TABLE `schema_migrations` (`version` varchar(255) NOT NULL PRIMARY KEY)
D, [2020-05-08T08:22:50.499390 #4] DEBUG -- :    (12.0ms)  CREATE TABLE `ar_internal_metadata` (`key` varchar(255) NOT NULL PRIMARY KEY, `value` varchar(255), `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL)
D, [2020-05-08T08:22:50.504699 #4] DEBUG -- :    (2.4ms)  SELECT GET_LOCK('410119075843185555', 0)
D, [2020-05-08T08:22:50.525145 #4] DEBUG -- :    (2.8ms)  SELECT `schema_migrations`.`version` FROM `schema_migrations` ORDER BY `schema_migrations`.`version` ASC
I, [2020-05-08T08:22:50.527632 #4]  INFO -- : Migrating to CreatePosts (20200407082548)
== 20200407082548 CreatePosts: migrating ======================================
-- create_table(:posts)
D, [2020-05-08T08:22:50.545176 #4] DEBUG -- :    (11.5ms)  CREATE TABLE `posts` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `content` text, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL)
   -> 0.0126s
== 20200407082548 CreatePosts: migrated (0.0128s) =============================

D, [2020-05-08T08:22:50.559351 #4] DEBUG -- :    (2.4ms)  BEGIN
D, [2020-05-08T08:22:50.562044 #4] DEBUG -- :   primary::SchemaMigration Create (2.5ms)  INSERT INTO `schema_migrations` (`version`) VALUES ('20200407082548')
D, [2020-05-08T08:22:50.573840 #4] DEBUG -- :    (11.5ms)  COMMIT
D, [2020-05-08T08:22:50.584601 #4] DEBUG -- :   ActiveRecord::InternalMetadata Load (3.2ms)  SELECT `ar_internal_metadata`.* FROM `ar_internal_metadata` WHERE `ar_internal_metadata`.`key` = 'environment' LIMIT 1
D, [2020-05-08T08:22:50.595802 #4] DEBUG -- :    (2.5ms)  BEGIN
D, [2020-05-08T08:22:50.598379 #4] DEBUG -- :   ActiveRecord::InternalMetadata Create (2.4ms)  INSERT INTO `ar_internal_metadata` (`key`, `value`, `created_at`, `updated_at`) VALUES ('environment', 'production', '2020-05-08 08:22:50', '2020-05-08 08:22:50')
D, [2020-05-08T08:22:50.607963 #4] DEBUG -- :    (9.4ms)  COMMIT
D, [2020-05-08T08:22:50.610566 #4] DEBUG -- :    (2.4ms)  SELECT RELEASE_LOCK('410119075843185555')
```

これで、デプロイは完了です。あとは実際にデプロイできている確認してみましょう。`heroku apps:info`というコマンドを入力してください。下記のように、公開されたアプリケーションの詳細を見ることができます。

```ruby:ターミナル
% heroku apps:info

==アプリケーション名
Addons:         cleardb:ignite
Auto Cert Mgmt: false
Dynos:          web: 1
Git URL:        https://git.heroku.com/アプリケーション名.git
Owner:          sample@sample.com
Region:         us
Repo Size:      165 KB
Slug Size:      56 MB
Stack:          heroku-18
Web URL:        https:/アプリケーション名.herokuapp.com/
```
`Web URL: https://アプリケーション名.herokuapp.com/`の部分のURLへアクセスすれば、公開されたページを見ることができます。


# デプロイ済みのアプリケーションに変更修正を加えた場合
デプロイ済みのアプリケーションに変更修正を加えた場合は`github上で変更修正をcommitし、ブランチを作成していた場合は、masterブランチへマージします。`その後、【手順６】Herokuへアプリケーションの情報をpushする→【手順７】Heroku上でマイグレーションを実行するを行うだけなので、変更修正はとても簡単ですね！

#もし、デプロイしてエラーが出てしまったら？？
最後に、デプロイ後のエラー対処方法についてです。エラーが出てしまっても、`エラーログ`をよく読むことでエラーを解決する事ができます。エラーログの出し方はターミナルに下記のように入力することで出す事ができます。

```ruby:ターミナル
heroku logs --tail --app アプリケーション名
```

すると、以下のようなログが表示されます。

```ruby:ターミナル
2020-05-08T09:03:30.572301+00:00 app[web.1]: F, [2020-05-08T09:03:30.572206 #4] FATAL -- : [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]
2020-05-08T09:03:30.572302+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e] ActionView::Template::Error (undefined method `checked' for #<Post:0x000055f0ec57ec88>):
2020-05-08T09:03:30.572303+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]      7: <div id="list">
2020-05-08T09:03:30.572303+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]      8: </div>
2020-05-08T09:03:30.572304+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]      9: <% @posts.each do |post| %>
2020-05-08T09:03:30.572305+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]     10:   <div class="post" data-id = <%= post.id %> data-check=<%= post.checked %>>
2020-05-08T09:03:30.572305+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]     11:     <div class="post-date">
2020-05-08T09:03:30.572306+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]     12:       投稿日時：<%= post.created_at %>
2020-05-08T09:03:30.572306+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]     13:     </div>
2020-05-08T09:03:30.572306+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e]
2020-05-08T09:03:30.572307+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e] app/views/posts/index.html.erb:10
2020-05-08T09:03:30.572307+00:00 app[web.1]: [52bf1bef-ea70-4df0-897a-6d0c3d925b1e] app/views/posts/index.html.erb:9
2020-05-08T09:03:30.574057+00:00 heroku[router]: at=info method=GET path="/" host=ajax-app-123456.herokuapp.com request_id=52bf1bef-ea70-4df0-897a-6d0c3d925b1e fwd="125.12.120.68" dyno=web.1 connect=1ms service=79ms status=500 bytes=1827 protocol=https
2020-05-08T09:03:31.014022+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=ajax-app-123456.herokuapp.com request_id=56eb5531-4288-48d7-9614-b58fed6deb86 fwd="125.12.120.68" dyno=web.1 connect=2ms service=2ms status=304 bytes=48 protocol=https
```
上記のエラーログだと、2行目に`undefined method 'checked'`とあるのでcheckedをdefで定義した後、上述したようにデプロイをすれば解決すると思います。

#まとめ
今回はデプロイの方法をまとめました。今後サービスをネットワーク上に公開したい人はぜひ参考にしてみてください！