🦁

Rails 8で本番利用可能になったSQLiteをつかうとGoogle Cloudでほぼ無料で運用ができそうな件

2025/01/30に公開
3

はじめに

Rails 8が新たにリリースされ、SQLiteを本番環境でも使用できるようになりました。
これまで、Google CloudでRailsアプリを運用する際、Cloud RunとCloud SQLを使うと簡単に構築できて便利だったんですが、Cloud SQLだけで最低月2,000円弱かかってしまっていました。
SQLiteは、PostgreSQLやMySQLと違いライブラリとして動作するため、データファイルを保存できるストレージがあれば別途CloudSQLなどのサービスを使う必要がなくなります。
なので、Cloud StorageのバケットにSQLiteのデータを置いて、Cloud RunでGCSバケットをボリュームマウントとして設定することで、ほぼ無料のRails環境が作れそうと考えて試してみました。

インフラ構成

Cloud RunとCloud Storageの構成にしています。Secret Managerは、Railsのmaster keyのために使っていますが、直接設定する場合は不要になります。

Railsアプリ作成

  • 確認用にmyAppという最小限のRailsアプリを作成します。
mkdir myApp
cd myApp
bundle init
  • GemfileにRails 8を指定
Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

gem "rails", "8.0.1"
  • Rails new
bundle exec rails new .
  • 投稿機能を作成します
bundle exec rails g scaffold post content:text
config/routes.rb
...
  root "posts#index"
...

データベースの設定は、下記のようにstorageディレクトリ以下にsqliteのデータを保存するようになります。

config/config.rb
default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: storage/development.sqlite3

test:
  <<: *default
  database: storage/test.sqlite3

production:
  primary:
    <<: *default
    database: storage/production.sqlite3
  cache:
    <<: *default
    database: storage/production_cache.sqlite3
    migrations_paths: db/cache_migrate
  queue:
    <<: *default
    database: storage/production_queue.sqlite3
    migrations_paths: db/queue_migrate
  cable:
    <<: *default
    database: storage/production_cable.sqlite3
    migrations_paths: db/cable_migrate

  • DB作成&マイグレート
bundle exec rails db:create
bundle exec rails db:migrate
  • ローカル環境で動作確認
bundle exec rails s

ブラウザでlocalhost:3000を開くとPost一覧が表示されます。

Google Cloudの準備

Cloud Storageバケット作成

SQLiteのデータを保管するストレージ用のバケットを作成します。

Secret ManagerにMasterKeyを保存

"rails_master_key"という名称で、config/master.keyの値を登録します。

デフォルトのサービスアカウントに権限を付与

Cloud RunからSecret Managerにアクセスするために、デフォルトのサービスアカウントにSecret Managerアクセサーロールを付与しておきます。

Artifact Repositoryの準備

  • Artifact Repository APIを有効にする

リポジトリを作成

"リポジトリの作成"をクリックして、リポジトリを作成しておきます。

リポジトリ名とリージョンを設定

最小コストを確認したいので、脆弱性スキャンは無効にしてます。

イメージをデプロイ

gcloudコマンドとdockerコマンドを使って、Docker imageをArtifact Repositoryにプッシュします。

  • Google Cloudにログイン
gcloud auth login
  • ArtifactiRepositoryのホストにasia-northeast1を追加
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
  • 定数設定
PROJECT_ID=myapp
REPOSITORY_NAME=myapp-repository
SERVICE_NAME=myapp
  • イメージをビルド
docker build -t asia-northeast1-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$SERVICE_NAME:1 .
  • イメージをプッシュ
docker push asia-northeast1-docker.pkg.dev/$PROJECT_ID/$REPOSITORY_NAME/$SERVICE_NAME:1
  • イメージがプッシュされたことを確認する

デプロイ

Cloud Runにデプロイ

  • コンテナをデプロイからサービスを選択します。

  • 「既存のコンテナイメージから1つのリビジョンをデプロイする」を選択します。
    コンテナイメージのURLには、先ほどArtifact Repositoryに登録したコンテナイメージを選択します。
    サービス名、リージョンをそれぞれ設定します。

  • 認証を「未認証の呼び出しを許可」にします。

  • コンテナタブのコンテナポートを3000ポートにします。

  • ボリュームタブの新しいボリュームで、以下を設定します。

    • ボリュームタイプ:Cloud Storageバケット
    • ボリューム名:database
    • バケット: [先ほど作成したバケット]

  • コンテナタブに戻って、「ボリュームのマウント」を開き先ほど設定したボリュームを選択します。
    マウントパスは、"/rails/storage"を設定します。

  • 続けて、「変数とシークレット」タブのシークレットにRAILS_MASTER_KEYを登録します。

  • リビジョンスケーリングのインスタンスの最小数を0、インスタンスの最大数を1にします。

  • 「作成」をクリックして、デプロイします。

しばらく待って、緑のチェックがつくとデプロイ成功です。
エラーになってしまう場合は、「新しいリビジョンの編集とデプロイ」から確認修正し再度デプロイしてください。

デプロイが成功すると、サービス詳細に表示されるURLからRailsアプリを開くことができます。

これで、最小限の構成のRailsアプリをデプロイできました。

確認

アプリの動作確認

Cloud RunのデフォルトURLからRailsアプリを確認します。

簡単な確認しかしていませんが、問題なく動作しました。

Cloud Storageのバケットを確認

Cloud Storageのバケットを確認するとsqliteのファイルが作成されます。
バケットの設定を間違えて公開しないよう注意しましょう。

費用確認

1週間くらい放置して費用の確認をしました。1日あたり0.1円ぐらい掛かっているので、月3円ぐらい課金されそうです。
内訳は、すべてArtifact Repositoryでした。Artifact Repositoryのストレージの無料枠(0.5GB)を少し超えているために課金されていると思われます。

その他

コールドスタートについて

Cloud Runの最小インスタンスを0にしているので、しばらくアクセスがないとコールドスタートの状態になります。体感としては、20秒程度かかった気がします。
今回は、実施しませんが稼働時間チェック(Cloud Monitoringによるヘルスチェック)を使っていると、ほとんど無視できると思いますが、インスタンスの稼働時間が増えるので費用が発生する可能性があります。

スケールアウトの制限

SQLiteが単一ホストが前提というところがあるので、Cloud Runのメリットであるスケールアウト(水平スケール)については諦める必要があります。もし、スケールアウトして複数インスタンスで稼働したい場合は、今のところPostgresqlやMySQLを使う方が良さそうです。

まとめ

Rails8 + SQLiteをCloud RunとCloud Storageで、月3円ぐらいで運用できそうです。
デモ用の小規模なアプリやポートフォリオ用アプリを安く運用したいというニーズには合うかもと思いました。

Discussion

nabesannabesan

ありがとうございます。こちらの記事の通りに構築を進めることでRails環境を構築することができました。
3点ほど設定につまづく箇所がありましたので、共有いたします。

  • イメージをプッシュする際Unauthenticated request. Unauthenticated requests do not have permission "artifactregistry.repositories.uploadArtifacts"エラーが発生

  • docker push時にterminated: Application failed to start: "/rails/bin/docker-entrypoint": exec format errorエラーが発生

    • Dockerイメージがビルドされたシステムと実行されるシステムのCPUアーキテクチャの不一致で発生するようです(こちらの環境はM1 Macでした)。以下のようにターゲットプラットフォームを指定することで解決できました。

    • FROM --platform=linux/x86_64 docker.io/library/ruby:$RUBY_VERSION-slim AS base

  • Cloud runのデプロイ時に ArgumentError: No database file specified. Missing argument: database (ArgumentError)が発生

    • database.ymlでproduction環境のdatabaseの設定が不足していたため発生したようです
    • database: storage/production.sqlite3のように設定を追加することで解決できました。

上記、参考になりましたら幸いです。

KiyoKatoKiyoKato

docker imageをpushする設定などで不足している部分があったようです。コメントを参考に追記させていただきました。
コメントありがとうございます。

nabesannabesan

改めて読み返したところ、databaseの設定は見逃しておりました。すみません 🙏