LaravelアプリケーションをHerokuにデプロイしてみよう

これは株式会社マイホム [アドベントカレンダー2024](https://qiita.com/advent-calendar/2024/myhm)の24日目の記事です。
記事の内容は会社の業務とは一切関係ありません。

## 概要

タイトル通りLaravelアプリケーションをHerokuにデプロイできるようにします。
n番煎じかもわかりませんが、各々記事毎に微妙に構成やバージョン違ってたり、公式ドキュメントに至っては（2024-12現在）Laravel5で書かれていたりもしますので、こんなんなんぼあっても良いですからねの精神で書いてみます。

## 前提

必要なものが入っていないMac一丁の状態からデプロイするところまで書けたら良かったのですが、途中まで書いてみてさすがに冗長過ぎるなと思い、それぞれに参考記事も数多ある以下の要素は前提条件として省略させていただくことにしました。

- Macに[Homebrew](https://brew.sh/ja/)をインストール済み
- Gitをインストール&セットアップ済み
- PHP, Composerをインストール済み
    - (optional)ネイティブインストールしたくないなという方は、代わりにdockerをインストールでもOK
- Herokuに有効なアカウントを登録済み、且つクレジットカード等の支払い情報を登録済み
- [Heroku CLI](https://devcenter.heroku.com/ja/articles/heroku-cli#install-the-heroku-cli)をインストール済み
- バージョンはPHP8.4, Laravel:11.5 を使用しています

## 手順

### ProcfileとLaravelアプリケーションの準備

#### Laravelアプリケーションの作成
```shell
 # ネイティブインストールのcomposerの場合
 % composer create-project laravel/laravel laravel-heroku-app

 # dockerコンテナから実行する場合
 % docker pull composer
 % run --rm -it -v $(pwd):/app -w /app composer composer create-project laravel/laravel laravel-heroku-app
```
#### Procfile作成
[Procfileドキュメント](https://devcenter.heroku.com/ja/articles/procfile)
`Procfile`は起動時にアプリケーションで実行するコマンドを指定するファイルです。
このファイルはアプリケーションのルートディレクトリに配置する必要があります。
```shell
% cd laravel-heroku-app
% echo "web: heroku-php-apache2 public/" > Procfile
```
詳細はリンク先のドキュメントで確認していただいた方が確実ですが、この内容をざっくり解説します。
Herokuで実行中のプログラムをプロセスと言います。
Procfileは各行で `<プロセスタイプ>: <コマンド>` という形式でプロセスタイプを宣言します。
HerokuアプリケーションにおいてwebプロセスタイプはHerokuのルーターからHTTPトラフィックを受信できる唯一のタイプです。
`heroku-php-apache2` コマンドはHerokuデプロイ中に自動で追加されるcomposerパッケージが提供するコマンドで、引数に指定した `public/` をドキュメントルートとしてwebサーバーを起動します。
やっていることはdockerでwebサーバーのコンテナを起動するのと大体同じですね。

#### Gitリポジトリを初期化&ソースをコミット
```shell
% git init
% git add .
% git commit -m "first commit."
```

### Herokuアプリケーション作成

引き続きカレントはアプリケーションのルートディレクトリのままで作業を続けます。

#### Herokuにログイン
```shell
% heroku login
```

ブラウザでログインしようとして、もし `IP address mismatch` が出てしまうようなら、以下のコマンドでCLIからクレデンシャルを直接入力してログインします。
```shell
% heroku login -i
```
このコマンドで求められるパスワードにはAPIキーを入力します。
APIキーはHerokuにブラウザでログインし、ユーザーアイコン > Account Settings > Accountタブ から取得することができます。

#### アプリケーションとリポジトリ作成

アプリケーション名は指定することもできますが、グローバル空間で全ユーザーと共有されているため、先に既存の名前と被っていると作成することができません。
後からでも変更できますので、とりあえず未指定のおまかせで作成をお勧めします。
**※アカウントに支払い情報を設定していないと作成できません。**
```shell
% heroku create
Creating app... done, ⬢ xxxxx-xxxxx-12345
https://xxxxx-xxxxx-12345-xxxxxxxxx.herokuapp.com/ | https://git.heroku.com/xxxxx-xxxxx-12345.git
```

作成に成功するとGitのリモートリポジトリとしても設定してくれます。

```shell
# リモートリポジトリ確認
% git remote -v
heroku	https://git.heroku.com/xxxxx-xxxxx-12345.git (fetch)
heroku	https://git.heroku.com/xxxxx-xxxxx-12345.git (push)
```

アプリケーションをHerokuにデプロイします。
```shell
% git push heroku main
```
ビルド＆デプロイが成功するとHerokuのアクティビティにこのようなビルドログが出てきます。
![2024-12-24_18-41-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260612/345cb263-3a50-3a26-135d-93182033859d.png)


#### DBの準備

お試しで使う程度なら、なるべくお安く抑えたいところです。
そこで無料プランがあるMySQLサーバーのリソースを提供してくれる[アドオン](https://elements.heroku.com/addons)はないかなと探していくと、[JawsDB](https://elements.heroku.com/addons/jawsdb)というアドオンが真っ先に出てくるのでこちらを使用することにします。

[JawsDB MySQLドキュメント](https://devcenter.heroku.com/articles/jawsdb)
※このドキュメント、アドオンの追加に関してはあまり親切ではなくて、アドオンの追加コマンドはあれど、プランの指定方法がこちらには載ってなかったりする（アドオンの詳細ページの方にちょろっと載ってます）ので、あまりCLIでの操作を想定していないのかもしれません。

一応コマンドでの追加方法を書きますが、ブラウザでログインしwebコンソールの方から設定した方がやりやすいと思います。
※この操作も支払い情報の登録がないと失敗します。
```shell
% heroku addons:create jawsdb:kitefin
Creating jawsdb:kitefin on ⬢ xxxxx-xxxxx-12345... free
Resource is being provisioned.
jawsdb-xxx-xxx is being created in the background. The app will restart when complete...
Use heroku addons:info jawsdb-xxxxxxxx-xxxxxxxx to check creation progress
Use heroku addons:docs jawsdb to view documentation
# アドオンの状態確認
% heroku addons

 Add-on                            Plan    Price Max price State   
 ───────────────────────────────── ─────── ───── ───────── ─────── 
 jawsdb (jawsdb-xxxxxxxx-xxxxxxxx) kitefin free  free      created 
  └─ as JAWSDB                                                     
                                                                   
The table above shows add-ons and the attachments to the current app (xxxxx-xxxxx-12345) or other apps.
```

#### 環境変数の設定

この作業も `heroku config:set` コマンドで実行できますが、webコンソールでアプリケーションの Settings > Config Vars からでも設定することができます。

まずLaravelの稼働に使用する暗号化鍵を生成します。

```shell
# ネイティブインストールのPHPの場合
% php artisan key:generate --show
# dockerコンテナでから実行する場合
% docker pull php
% docker run --rm -it -v $(pwd):/app -w /app php php artisan key:generate --show
```

生成した暗号化鍵を環境変数として設定します。

```shell
% heroku config:set APP_KEY=<暗号化鍵>
Setting APP_KEY and restarting ⬢ xxxxx-xxxxx-12345... done, v3
APP_KEY: <暗号化鍵>
```

DBの環境変数を設定します。
アドオンから必要な情報を収集します。
[ドキュメント](https://devcenter.heroku.com/articles/jawsdb)に記載の通りこのコマンドで表示される値は下記の構成になっていますので、ここから値を設定していきます。
```shell
% heroku config:get JAWSDB_URL
mysql://username:password@hostname:port/default_schema
% heroku config:set DB_CONNECTION=mysql
% heroku config:set DB_USERNAME=username
% heroku config:set DB_PASSWORD=password
% heroku config:set DB_HOST=hostname
% heroku config:set DB_PORT=port
% heroku config:set DB_DATABASE=default_schema
```

DB関連の環境変数を一通り設定したらマイグレーションを実行します。
```shell
% heroku run php artisan migrate
```
APP_ENVを設定していないとデフォルトではproductionとして扱われますので、確認に対してyesを選択して実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260612/fdb6da2e-4760-4c69-5f33-ff62281f7a5d.png)


最後にエラーログをHeroku側で拾えるようにログの出力先も設定しておきましょう。

```shell
% heroku config:set LOG_CHANNEL=errorlog
# 設定した環境変数を確認
% heroku config
```

### 動作確認
ブラウザで動作していることを確認します。

```shell
# 標準ブラウザが起動します
% heroku open
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260612/e6c4689a-b3eb-945b-a423-03f757fbdabd.png)

以上でアプリケーションのデプロイ完了です。