Heroku から Fly.io へ Laravel アプリケーションのマイグレーション

　数年前、プライベートウェブサイト用として Heroku にデプロイしてあった Laravel アプリケーションを、今回、Fly.io へマイグレーション（移行）したので、その際に必要になった作業を残しておこうと思います。

:::note info
Heroku の名前の由来は、 **"Hero"** と **"Haiku"** を結合させたものと Wikipedia には説明されていましたが、それは、Heroku の開始当初は Ruby on Rails 用の PaaS だったからです。Fly.io も随所に（英語の）**俳句**がしたためられていて、私もこの俳句を見てマイグレーション先に Fly.io を選択しました。

https://fly.io/app/sign-up
![codepopel1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1486355/53f46674-922f-9e27-bf2e-1846dc4ea9e2.jpeg)
:::
<br>
<br>

***
### 自動でマイグレーション（移行）する
***

　まず１つ目は、<strong>「Heroku から Fly.io へのマイグレーションには、Fly.io に "Turbocharge" 機能」</strong>が用意されている事です。何だかんだで、私は一日がかりでマイグレーションしたのですが、この Turbocharge 機能を知っていれば、ものの数分で終わったかも知れませんでした。

:::note warn
Heroku から Fly.io への<strong>自動マイグレーション（移行）機能</strong>

https://fly.io/launch/heroku
![turbocharge.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1486355/9251aad1-14fe-3d68-4c6a-aedb0e21ffe4.jpeg)

:::
<br>
<br>

***
### PHP と Laravel のバージョンを合わせる
***

　このセクションを読み進めているという事は、冒頭の Turbocharge でマイグレーションできなかったという事だと思います。私が Heroku へデプロイしてあったアプリケーションは、PHP7.2、Laravel/Framework6.2 でした。2023年7月12日現在で、これを PHP8.1、Laravel/Framework10.10 に <strong>composer update</strong> して、Fly.io へマイグレーションする必要があります。

これを実行するには、まず、PHP8 をインストールします。

https://qiita.com/daizou33/items/6eac47ff5fde10b3c643

上記ウェブサイト等を参考にインストールする訳ですが、私の環境は、Ubuntu 20.04.5 LTS だった為なのか、微妙にバージョンが違っていました。手順を読み替えた部分は、以下の通りです。

:::note info
sudo apt-get install php8.1-xml
　→　sudo apt-get install php**8.2**-xml
:::

:::note info
sudo apt-get install php8.1-curl
　→　sudo apt-get install php**8.2**-curl
:::

そして、composer によってインストールされる Laravel/Framework は、10.10 です。
<br>

また、「Laravel7 から Laravel8 へのアップデート」を解説されているウェブサイトは多数あるので、それらを参考にアップデートしていきますが、非常に手間が掛かるので、私は、PHP と Laravel のインストールの際に作成する "example-app" の "composer.json" で置き換えて利用しました。アップデートする Laravel アプリケーションは、ローカルに残してあるものや、Heroku にアップロードしてあるものを取得して、手元に用意しておきます。

:::note info
"example-app" で作成される "composer.json" をマイグレーション対象のアプリケーションの "composer.json" と置き換える。
:::
<br>

更に、Laravel7 系と Laravel8 系では、ソースコード上にも非互換箇所があり、その部分はマニュアルで修正する必要があります。

:::note info
"app/Exceptions/Handler.php" の "Exception" を
　→　"Throwable" に変更し、

それに伴い、"use Exception;" も
　→ "use Throwable;" に変更する。

```php5:app/Exceptions/Handler.php
namespace App\Exceptions;

use Throwable;

.
.
.

class Handler extends ExceptionHandler
{

.
.
.

    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

    public function render($request, Throwable $exception)
    {
        return parent::render($request, $exception);
    }
}
```

:::

https://yoo-s.com/topic/detail/869

https://qiita.com/ntm718/items/c6bd9d8f189473b8d668

<br>

また、SMTP を設定している環境変数が変更されています。

:::note info
".env.sample" (もしくは、".env" )と、"config/mail.php" の

"MAIL_**DRIVER**" を
　→　"MAIL_**MAILER**" に修正します。

```shell:.env.sample
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
```

```php5:config/mail.php
/*
 |--------------------------------------------------------------------------
 | Mail Driver
 |--------------------------------------------------------------------------
 |
 | Laravel supports both SMTP and PHP's "mail" function as drivers for the
 | sending of e-mail. You may specify which one you're using throughout
 | your application here. By default, Laravel is setup for SMTP mail.
 |
 | Supported: "smtp", "sendmail", "mailgun", "ses",
 |            "postmark", "log", "array"
 |
*/
'driver' => env('MAIL_MAILER', 'smtp'),
```

:::

https://qiita.com/saitou311099/items/019034100593255407da

https://laracasts.com/discuss/channels/laravel/laravel-7-replaced-mail-driver-by-mail-mailer

一通り修正が終わったら、"composer update" を実行します。

:::note info
```shell-session
composer update
```
:::
<br>
<br>

***
### npm のバージョンを合わせる
***


　（運が良ければ、）上記修正で PHP/Laravel の "composer update" は完了ですが、Fly.io に launch すると、npm の lock file が古いと "**npm WARN old lockfile**" を出力してきます。

もちろん、警告がでなければ問題ありませんが、出ている場合は、まず、nvm がインストールされていなければ、nvm をインストールします。

https://tutorialcrawler.com/ubuntu-debian/ubuntu-20-04%E3%81%ABnvm%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/

そして、lock file の Warning を解消するために、下記コマンドを実行します。

:::note info
```
npm i --package-lock-only
```
:::

https://dev.classmethod.jp/articles/fix-npm-warn-on-cdk/

<br>

これで、lock file の問題は解消されました。また、node.js の OpenSSL でも "**ERR_OSSL_EVP_UNSUPPORTED**" エラーが出ているかも知れません。

https://zenn.dev/yogarasu/articles/425732ff408d06

その場合は、環境変数 "NODE_OPTIONS=--openssl-legacy-provider" を指定して実行するように、どのウェブサイトでも説明されています。Fly.io の場合、単に "export NODE_OPTIONS=..." としても効いていないので、"package.json" で指定します。

:::note info
package.json にある "scripts" セクションの各行（"dev","development","watch"...）に "**NODE_OPTIONS=--openssl-legacy-provider**" を追加する。
```json:package.json
{
    "private": true,
    "scripts": {
        "dev": "NODE_OPTIONS=--openssl-legacy-provider npm run development",
        "development": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "NODE_OPTIONS=--openssl-legacy-provider npm run development -- --watch",
        "watch-poll": "NODE_OPTIONS=--openssl-legacy-provider npm run watch -- --watch-poll",
        "hot": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "NODE_OPTIONS=--openssl-legacy-provider npm run production",
        "production": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.19",
        "cross-env": "^5.1",
        "laravel-mix": "^4.0.7",
        "lodash": "^4.17.13",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.15.2",
        "sass-loader": "^7.1.0"
    }
}

```
:::
<br>
<br>

***
### デプロイ
***

こちらも、一通り修正が終わったら、"flyctl launch" を実行します。Fly.io のレジストリがまだの方は、冒頭のリンクなどから登録します。

https://zenn.dev/imah/articles/a41e889dbf54da

:::note info
Fly.io コマンドラインツールのインストールと sign up、そして、アプリケーションの launch。 "flyctl launch" の中では、デプロイまでしてくれます。
```shell-session
curl -L https://fly.io/install.sh | sh
flyctl auth signup
flyctl launch
```
:::

（幸運にも、）何事もなく正常終了したなら、"flyctl open" でアプリケーションを開始して完了です。

:::note info
```
flyctl open
```
:::

　こうして全体を通して概観してみると、"Turbocharge" による自動マイグレーションができない場合は、非常に手間がかかることが、よく解ります。

**以上**