🙌

シングルインスタンスでSQLiteなRails 8アプリをFly.ioにデプロイする

2024/11/27に公開

Fly.ioのインスタンス(Machine)の実行時間に応じて課金されます。
そしてauto_stop_machinesを有効にすることで、アプリがアクセスされないときにインスタンスが停止され、その間は課金が発生しません。
(※停止時でもファイルシステム課金は発生します)

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

またFly.ioはファイルシステム(Volume)をMachineにアタッチできます。
Railsアプリのコンテナ内でredis-serverを起動し、データベースはSQLite3に保存します。
これにより、従来のPaaSよりランニングコストを抑えられ、VPSよりも簡単にデプロイできます。

デメリットとしては、停止時間が発生するため、定期的にジョブを実行するアプリでは停止時間が最大化できなくてコスト効率が悪いです。
またシングルインスタンスなので、複数台に負荷分散するスケールアウトができません。ただし、単一のMachineのスケールアップして1台あたりのスループットを向上することは可能です。

本記事では37signalsが公式に提供しているWritebookというシンプルなCMSのRailsアプリをFly.ioにデプロイします。

https://once.com/writebook

まず、writebook.zipをダウンロードして解凍し、ディレクトリに移動します。

次に、Fly.ioの設定ファイルを作成します

fly launch

RAMサイズは1024MBで設定します

fly.toml
app = "<YOUR_APP_NAME>"

primary_region = "nrt" # Tokyo

volumeを作成します。デフォルトの1GBで問題ありません

fly vol create -r nrt -y sqlite3_volume

writebookのドキュメントではDigitalOceanやHetnzerのVPSへのデプロイが推奨されています。
Pumaの前段にThrusterが起動するようになっていますが、Fly.ioでは不要なので剥がします。

Gemfile
 gem "bcrypt", "~> 3.1.7"
 gem "image_processing", "~> 1.13"
 gem "rqrcode"
-gem "thruster"
 gem "useragent", github: "basecamp/useragent"
 gem "front_matter_parser"
Procfile
-web: bundle exec thrust bin/start-app
+web: bundle exec puma -C config/puma.rb
[env]
  WEB_CONCURRENCY = "1"
  PORT = "3000"
  
[[services]]
  internal_port = 3000
  protocol = "tcp"
  auto_stop_machines = "stop"
  auto_start_machines = true
  min_machines_running = 0
  
  [[services.ports]]
    handlers = ["http"]
    port = "80"
    force_https = true

  [[services.ports]]
    handlers = ["tls", "http"]
    port = "443"
Dockefile
 # Start the server by default, this can be overwritten at runtime
-EXPOSE 80 443
+EXPOSE 3000
 CMD ["bin/boot"]

bin/bootからはProcfileにあるコマンドが同一のコンテナで実行されます
redis-serverとresque-poolがすでに定義されているのでこのままでOKです
外部のredis-serverの追加は不要です

Procfile
-web: bundle exec thrust bin/start-app
+web: bundle exec puma -C config/puma.rb
web: bundle exec puma -C config/puma.rb
redis: redis-server config/redis.conf
workers: FORK_PER_JOB=false INTERVAL=0.1 bundle exec resque-pool

最後にSQLite3のデータベースをvolumeにマウントします

[env]
  WEB_CONCURRENCY = "1"
  PORT = "3000"
  DATABASE_URL = "sqlite3:///rails/storage/db/production.sqlite3"

[[mounts]]
  source = "sqlite3_volume"
  destination = "/rails/storage"
production:
  primary:
    <<: *default
    database: <%= ENV['DATABASE_URL'] %>

マイグレーションをデプロイのタイミングで実行するためには、release_commandを利用します

[deploy]
  release_command = "bin/rails db:prepare"

Fly.ioにデプロイします

fly deploy

デプロイできました。

サインアップしてCMS機能が一通り動作することを確認します。

その後、auto_stop_machinesが有効になっているので、アクセスがないときはインスタンスが停止されます。
そしてアクセスがあると自動的に起動することを確認します

Discussion