Rails + SQLite3 + React プロジェクトをGoogle Cloud Run にお安くデプロイする

GCPに興味はあるけれど、DB料金がお高くて個人開発には厳しいな。。。と思っていたところ、

というTweetに出会いました。
SQLite + Litestreamでお安くGCPにデプロイできるというのです。
自分のような初心者には難度が高いかと思いましたが、先人の資料が充実していたので、挑戦してみることにしました。

目次

環境

  • wsl2
  • Debian 11.5
  • Ruby 3.1.1
  • Rails 7.0.4
  • React 18.2.0
  • SQLite3 3.34.1
  • Docker 20.10.21
  • Google Cloud SDK 412.0.0 alpha 2022.12.09 beta 2022.12.09 bq 2.0.83 bundled-python3-unix 3.9.12 core 2022.12.09 gcloud-crc32c 1.0.0 gsutil 5.17

設定

Googleアカウント

  • アカウントを用意します
  • アカウントに二要素認証を設定します

Cloud Strageのバケットを作成

Google Cloudの設定

Dockerfileの作成

  • Dockerfileを作成します
FROM ruby:3.1.1

ENV RAILS_ENV="production"
ENV NODE_ENV="production"

# Cloud Run default port 8080
EXPOSE 8080

# nodeをインストール
RUN curl -fsS https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs

# APTライブラリを更新してインストール
# aptキャッシュをクリーンする。yオプションですべての問い合わせにyes
# /var/lib/apt/lists/*を削除してイメージを減らす
# https://docs.docker.jp/engine/articles/dockerfile_best-practice.html
RUN apt-get update \
    && apt-get install -y --no-install-recommends sqlite3 \
    && apt-get -y clean \
    && rm -rf /var/lib/apt/lists/*

# Download the static build of Litestream directly into the path & make it executable.
# This is done in the builder and copied as the chmod doubles the size.
# ref: https://github.com/steren/litestream-cloud-run-example/blob/main/Dockerfile
ADD https://github.com/benbjohnson/litestream/releases/download/v0.3.9/litestream-v0.3.9-linux-amd64-static.tar.gz /tmp/litestream.tar.gz
RUN tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz

# working directoryの設定
WORKDIR /app

# リポジトリのファイルをコピー
COPY . /app

# gemのインストール
RUN bundle install

# アセットをプリコンパイルする
# コンパイルが終わったら不要なキャッシュと node_modules を消してイメージの容量を減らす
RUN SECRET_KEY_BASE=placeholder bundle exec rails assets:precompile \
 && rm -rf node_modules tmp/cache

# Copy Litestream configuration file & startup script.
COPY ./litestream.yml /etc/litestream.yml
COPY entrypoint.sh /app/entrypoint.sh

RUN chmod +x /app/entrypoint.sh

# public配下のファイルを公開する
ENV RAILS_SERVE_STATIC_FILES="true"
ENTRYPOINT ["/app/entrypoint.sh"]

entrypoint.shファイルの作成

  • entrypoint.shファイルを作成します
#!/bin/bash
set -e

# コンテナ起動時に持っているSQLiteのデータベースファイルは、
# 後続処理でリストアに成功したら削除したいので、リネームしておく
if [ -f /app/db/production.sqlite3 ]; then
  mv /app/db/production.sqlite3 /app/db/production.sqlite3.bk
fi

# Restore the database
- litestream restore -v -if-replica-exists -config /etc/litestream.yml /app/db/production.sqlite3

# リストアに成功したら、リネームしていたファイルを削除
if [ -f /app/db/production.sqlite3]; then
  echo "---- Restored from Cloud Storage ----"
  rm /app/db/production.sqlite3.bk
else
  # 初回起動時にはレプリカが未作成であり、リストアに失敗するので、
  # その場合には、冒頭でリネームしたdbファイルを元の名前に戻す
  echo "---- Failed to restore from Cloud Storage ----"
  mv /app/db/production.sqlite3.bk /app/db/production.sqlite3
fi

# server.pidが残ってしまって起動できなくなることを防ぐために削除する
# server.pid は、削除してもrails serverを実行した時に自動で作成される
rm -f /app/tmp/pids/server.pid

# Run litestream with your app as the subprocess.
exec litestream replicate -exec "rails server -p 8080 -b 0.0.0.0"

Litestreamの設定ファイルの作成

dbs:
  - path: /app/db/production.sqlite3
    replicas:
      - url: gcs://kankendb

.gcloudignore ファイルの作成

  • Cloud Runではコピー対象外のファイルは.gcloudignoreファイルで指定します
    .gcloudignoreは、.gitignoreに指定されているファイルも無視するので注意が必要ですが、

This .gcloudignore (similar to the one generated when Git files are present) would prevent the upload of the .gcloudignore file, the .git directory, and any files in ignored in the .gitignore file:
gcloud topic gcloudignore  |  Google Cloud CLI Documentation

.gcloudignore で一旦全部 ignore して、必要な特定のファイルやディレクトリだけを指定すれば、実行に必要ないファイルをアップロードせずに済みます
.gcloudignore で全部無視して必要なものだけ指定する - ぽ靴な缶

# ignore all
*

# directories
!app
!bin
!config
!db
!frontend
!lib
!node_modules
!public
!storage
!vendor

# ignore directories
frontend/src/__tests__

# files
!Dockerfile
!entrypoint.sh
!Gemfile
!Gemfile.lock
!package.json
!package-lock.json
!config.ru
!identifier.sqlite
!litestream.yml
!postcss.config.cjs
!Procfile.dev
!Rakefile
!tailwind.config.cjs
!tsconfig.json
!tsconfig.node.json
!vite.config.ts

デプロイ

  • 以下のコマンドでデプロイします
gcloud beta run deploy kanken-practice   \
--source .    \
--set-env-vars REPLICA_URL=gcs://kankendb/database   \
--max-instances 1   \
--execution-environment gen2   \
--no-cpu-throttling   \
--allow-unauthenticated   \
--region asia-northeast1   \
--project keikami

引数は

  • Litestreamは複数サーバとの互換性が無いため、最大1インスタンスにする
  • Cloud Run の第2世代を使用する
  • CPUが常に割り当てられるようにする
  • 認証されていない呼び出しを許可することで、サービスにアクセスできるようにする

の設定です
gcloud run deploy  |  Google Cloud CLI Documentation
GitHub - steren/litestream-cloud-run-example: An example of using Litestream within Cloud Run

デプロイ開始

⠛ Building and deploying... Uploading sources.                                                                                                         
  ⠛ Uploading sources...                                                                                                                               
  . Building Container...
  . Creating Revision...
  . Routing traffic...
  . Setting IAM Policy...

成功したようです

Done.                                                                                                                                                  
Service [kanken-practice] revision [kanken-practice-00159-jis] has been deployed and is serving 100 percent of traffic.
Service URL: https://kanken-practice-b5ve7zdnrq-an.a.run.app

動作確認

参考サイト

ソースコード

https://github.com/kei-kmj/kanken_practice_note