Fly.ioにデプロイしてみた

**mofmof Advent Calendar 2022** 5日目の記事となります。

株式会社mofmofのkomaです。
Herokuの無料プランが廃止となり、さまざまなPaaSに移行された方も多いのではないでしょうか。
本記事ではPaaSの一つである**Fly.io**へのデプロイ手順やコストについて共有したいと思います。

# Fly.ioとは
ユーザーの近くでフルスタックのアプリとデータベースを実行するためのプラットフォーム(直訳)。
東京リージョンもあるのがうれしいポイント。

# 環境
以下の環境で実際にデプロイを行いました。
- MacOS Monterey V12.6.1
- M1 MacBook Pro

# デプロイ手順

公式ドキュメントにRailsデプロイ手順があるので、こちらを参考に既存Railsアプリケーションのデプロイを行いました。
Dockerfileがなくても、ソースコードをスキャンして自動生成してくれるので同じ手順で進められます。

https://fly.io/docs/rails/getting-started/

まずはFlyを利用するにあたって必要となるCLIアプリをインストールします。
```
$ brew install flyctl
```

以下のコマンドでFlyのアカウント登録を行います。
メールかGitHubによる認証が選べますが、今回はGitHub認証を行いました。
```
$ flyctl auth signup
Opening https://fly.io/app/auth/cli/6848ce18ed0b4fbe889b3c9207f5c619 ...

Waiting for session... Done
successfully logged in as <メールアドレス>
```

コマンド実行後、以下の画面が表示されるので「Sign up with GitHub」をクリック
![スクリーンショット 2022-11-28 17.43.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317957/7f0b7b5c-7e34-4676-7561-d442819a31fb.png)

アカウント登録とログインが完了すると以下の画面が表示されます。
![スクリーンショット 2022-11-28 18.27.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317957/bc9b0936-31de-3807-def2-a640f0b26a91.png)


すでにアカウントを持っている場合は以下のコマンドでログインします。
```
$ flyctl auth login
Opening https://fly.io/app/auth/cli/ee15cd5d455fa720d1f2a9cbdffde460 ...

Waiting for session... Done
successfully logged in as <メールアドレス>
```

コマンドを実行したらクレジットカード情報が必要とのことなので登録します。
```
$ fly launch
Creating app in /Users/kmkkiii/Development/myapp
Scanning source code
Detected a Rails app
? Overwrite "/Users/kmkkiii/Development/myapp/Dockerfile"? Yes
? Choose an app name (leave blank to generate one): sample-rails-app
automatically selected personal organization: Your Name
? Choose a region for deployment: Tokyo, Japan (nrt)
Error We need your payment information to continue! Add a credit card or buy credit: https://fly.io/dashboard/your-name/billing
```

クレジットカード登録後、再度実行します。
ファイルを上書きするかどうか、PostgreSQLやRedisを利用するかどうかを聞かれるので`y`か`N`を入力してください。
```
$ fly launch
Creating app in /Users/kmkkiii/Development/myapp
Scanning source code
Detected a Rails app
? Overwrite "/Users/kmkkiii/Development/myapp/Dockerfile"? No
? Choose an app name (leave blank to generate one): sample-rails-app
automatically selected personal organization: Your Name
? Choose a region for deployment: Tokyo, Japan (nrt)
Created app sample-rails-app in organization personal
Set secrets on sample-rails-app: RAILS_MASTER_KEY
Wrote config file fly.toml
? Would you like to set up a Postgresql database now? Yes
? Select configuration: Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk
Creating postgres cluster in organization personal
Creating app...
Setting secrets on app sample-rails-app-db...
Provisioning 1 of 1 machines with image flyio/postgres:14.4
Waiting for machine to start...
Machine 4d89446c6d5487 is created
==> Monitoring health checks
  Waiting for 4d89446c6d5487 to become healthy (started, 3/3)

Postgres cluster sample-rails-app-db created
  Username:    postgres
  Password:    2CYDQgLME6y6cCo
  Hostname:    sample-rails-app-db.internal
  Proxy port:  5432
  Postgres port:  5433
  Connection string: postgres://postgres:2CYDQgLME6y6cCo@sample-rails-app-db.internal:5432

Save your credentials in a secure place -- you won't be able to see them again!

Connect to postgres
Any app within the Your Name organization can connect to this Postgres using the following connection string:

Now that you've set up postgres, here's what you need to understand: https://fly.io/docs/reference/postgres-whats-next/

Postgres cluster sample-rails-app-db is now attached to sample-rails-app
The following secret was added to sample-rails-app:
  DATABASE_URL=postgres://myapp_on_fly:p2aPPtqwBv0xvU3@top2.nearest.of.sample-rails-app-db.internal:5432/myapp_on_fly?sslmode=disable
Postgres cluster sample-rails-app-db is now attached to sample-rails-app
? Would you like to set up an Upstash Redis database now? Yes
? Select an Upstash Redis plan Free: 100 MB Max Data Size

Your Upstash Redis database sample-rails-app-redis is ready.
Apps in the personal org can connect to at redis://default:c077a344694b4b25a63d97ad1ab5fc23@fly-sample-rails-app-redis.upstash.io
If you have redis-cli installed, use fly redis connect to connect to your database.

Redis database sample-rails-app-redis is set on sample-rails-app as the REDIS_URL environment variable

Your Rails app is prepared for deployment.

If you need custom packages installed, or have problems with your deployment
build, you may need to edit the Dockerfile for app-specific changes. If you
need help, please post on https://community.fly.io.

Now: run 'fly deploy' to deploy your Rails app.
```

:::note info
デプロイに失敗した場合はプロセスが残ってしまっている場合があるので、
`rm -f tmp/pids/server.pid`をDockerfileに追加すると解消する場合があります。
:::

準備ができたのでいざ、デプロイ！
```
$ fly deploy
==> Verifying app config
--> Verified app config
==> Building image
Remote builder fly-builder-nameless-dawn-4597 ready
==> Creating build context
--> Creating build context done
==> Building image with Docker
--> docker host: 20.10.12 linux x86_64
[+] Building 0.3s (0/1)
[+] Building 78.7s (10/11)
 => [internal] load remote build context                                                                       0.0s
 => copy /context /                                                                                            0.1s
 => [internal] load metadata for docker.io/library/ruby:latest                                                 3.1s
 => [1/8] FROM docker.io/library/ruby@sha256:67fb105998e2a5b61cdb43ce652494d28c848515826160c6c2e755c93af71ad  15.1s
 => => resolve docker.io/library/ruby@sha256:67fb105998e2a5b61cdb43ce652494d28c848515826160c6c2e755c93af71ada  0.0s
 => => sha256:3cb3f18bcb199397b36c68158d9374e051aeedad641fb8923a90929ba64ea8db 199B / 199B                     1.5s
 => => sha256:67fb105998e2a5b61cdb43ce652494d28c848515826160c6c2e755c93af71ada 1.86kB / 1.86kB                 0.0s
 => => sha256:16b10901a3efff0654fff7459165dd512fa97b3d1f79da577597d4388639d6ef 2.00kB / 2.00kB                 0.0s
 => => sha256:a8ca11554fce00d9177da2d76307bdc06df7faeb84529755c648ac4886192ed1 55.04MB / 55.04MB               2.8s
 => => sha256:e4e46864aba2e62ba7c75965e4aa33ec856ee1b1074dda6b478101c577b63abd 5.16MB / 5.16MB                 1.7s
 => => sha256:195ea6a58ca87a18477965a6e6a8623112bde82c5b568a29c56ce4581b6e6695 54.59MB / 54.59MB               5.1s
 => => sha256:046e6d725a3c4395ae7985dead42e5480f8b917deaca34cb398532742351be75 7.29kB / 7.29kB                 0.0s
 => => sha256:c85a0be79bfba309d1f05dc40b447aa82b604593531fed1e7e12e4bef63483a5 10.88MB / 10.88MB               2.4s
 => => sha256:157f16ed0a0c119e5015d22d95fd158bf9e85654611b870b79cca3987442948b 196.87MB / 196.87MB             7.7s
 => => sha256:9b1efc16061ba8c2f99efe4a066792f78d4a03c2c40d01dbe84e1a44bf58ed12 32.59MB / 32.59MB               4.4s
 => => sha256:c9c081f4a2ff8a8b3b9aaba8158aea5f5051d43dddec05d8c186128b384aac55 175B / 175B                     1.4s
 => => extracting sha256:a8ca11554fce00d9177da2d76307bdc06df7faeb84529755c648ac4886192ed1                      1.8s
 => => extracting sha256:e4e46864aba2e62ba7c75965e4aa33ec856ee1b1074dda6b478101c577b63abd                      0.2s
 => => extracting sha256:c85a0be79bfba309d1f05dc40b447aa82b604593531fed1e7e12e4bef63483a5                      0.3s
 => => extracting sha256:195ea6a58ca87a18477965a6e6a8623112bde82c5b568a29c56ce4581b6e6695                      2.5s
 => => extracting sha256:157f16ed0a0c119e5015d22d95fd158bf9e85654611b870b79cca3987442948b                      5.9s
 => => extracting sha256:3cb3f18bcb199397b36c68158d9374e051aeedad641fb8923a90929ba64ea8db                      0.0s
 => => extracting sha256:9b1efc16061ba8c2f99efe4a066792f78d4a03c2c40d01dbe84e1a44bf58ed12                      0.8s
 => => extracting sha256:c9c081f4a2ff8a8b3b9aaba8158aea5f5051d43dddec05d8c186128b384aac55                      0.0s
 => [2/8] RUN apt-get update -qq &&     apt-get install -y build-essential libpq-dev nodejs npm vim &&     n  54.5s
 => [3/8] RUN mkdir /myapp                                                                                     0.3s
 => [4/8] WORKDIR /myapp                                                                                       0.0s
 => [5/8] ADD Gemfile /myapp/Gemfile                                                                           0.0s
 => [6/8] ADD Gemfile.lock /myapp/Gemfile.lock                                                                 0.0s
 => ERROR [7/8] RUN bundle install                                                                             5.5s
------
 > [7/8] RUN bundle install:
#10 0.386 Bundler 2.3.26 is running, but your lockfile was generated with 2.3.7. Installing Bundler 2.3.7 and restarting using that version.
#10 3.387 Fetching gem metadata from https://rubygems.org/.
#10 3.626 Fetching bundler 2.3.7
#10 5.067 Installing bundler 2.3.7
#10 5.429 Your Ruby version is 3.1.3, but your Gemfile specified 3.1.2
------
Error failed to fetch an image or build from source: error building: executor failed running [/bin/sh -c bundle install]: exit code: 18
```

bundlerのバージョンが違うと言われたので、fly.tomlファイルにバージョンを設定します。
```diff:fly.toml
# fly.toml file generated for sample-rails-app on 2022-12-03T10:55:16+09:00

app = "sample-rails-app"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[build]
  [build.args]
+   BUNDLER_VERSION = "2.3.7"
    BUILD_COMMAND = "bin/rails fly:build"
    SERVER_COMMAND = "bin/rails fly:server"
```

無事デプロイできました！簡単ですね。

# 気になるコスト
従量課金制のHobbyプランで始まりますが、
Hobbyプラン含め全てのプランに対して無料で使用できるリソースがあります。
## 無料枠
> Free Allowances
Resources included for free on all plans:
>- Up to 3 shared-cpu-1x 256mb VMs
>- 3GB persistent volume storage (total)
>- 160GB outbound data transfer

- 共有CPUでメモリ256MBのVMが最大3つまで
- ３GBの永続ストレージボリューム(合計なので分割できる)
- 160GBのアウトバウンドデータ転送(インバウンドは無料)

メモリがHerokuのEco Dynoプランの半分なので心許ないかもしれません...。
90日で停止したり、一定時間操作しないとスリープしたりするような制限なくPostgreSQLが使えるのはいいですね！

上記リソース以上を使用した場合は、その使用量に応じて料金を支払います。
デプロイしたアプリでOOMが発生してメモリをスケールした場合、
そのメモリに応じて1秒あたりの料金が変わるので無料枠の＄5.82を超えた分が請求されます。
> 無料枠： ＄1.94/月 × 3（VM数) = ＄5.82

料金体系はVMと永続ストレージボリューム、ネットワークでそれぞれ異なるため、詳細は以下をご確認ください。

https://fly.io/docs/about/pricing/

## Redisも使える
Redisも100MBのデータサイズまでは無料で使えるみたいなので、sidekiqによるバックグラウンド処理も実行できそうです。

https://fly.io/docs/rails/the-basics/sidekiq/


## Hobbyの他3つの価格プラン
### Launch
専用CPUのVMなど$29/月分のリソースとメールサポートが受けられるプランです。
### Scale
$199/月分のリソースと優先メールサポート、HIPAA(コンプライアンス要件)/BAA(事業提携契約)のサポート等が受けられる組織向けプランです。
### Emterprise
カスタマイズや緊急サポートが受けられる企業向けプランです。

## Autoscaling
デフォルトでは無効となっているのでひとまず安心です。
```
$ fly autoscale show
    Autoscaling: Disabled
```

## 請求内容の確認
使用量や請求内容は、Fly.ioのDashboard→Billingから確認できます。
![スクリーンショット 2022-12-03 14.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317957/f56c117c-7c21-6ec4-6734-2e42ec69cb8b.png)


# 最後に
CLIで簡単にデプロイでき、コストもある程度の規模であれば無料枠内で収まりそうなので、
個人開発アプリのデプロイ先としてもよいかもしれませんね。