RailsアプリをCloud Runにデプロイする最短手順 2023

株式会社エイチームフィナジーの@okonomiです。
この記事は[Ateam Finergy Inc. × Ateam Wellness Inc. Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ateam-finergy-wellness)の2日目の投稿です。

普段の業務ではCloud RunにRailsアプリをデプロイして運用しています。
検証のためにテストアプリを作ってCloud Runにデプロイすることがときどきあって、毎回調べながらやってる気がするので最低限の手順をまとめておこうと思います。

今後のアップデートで手順が変わるかもしれないので2023年版としています。

:::note warn
今回デプロイするアプリは手順をシンプルにするためアクセス制限を設けていません。URLが分かれば誰でもアクセスできます。公開してはいけない情報を含めないようにしてください。
:::

# 環境など

いずれも記事作成時点での最新バージョンです。

- Ruby 3.2.2
- Rails 7.1.2
- Google Cloud CLI 455.0.0

また、デプロイするRailsアプリはproductionモード（RAILS_ENV=production）で動作するように設定していきます。

# 準備

事前にGoogle Cloud CLIのセットアップを完了しておいてください。

https://cloud.google.com/sdk/docs/install-sdk?hl=ja

# 手順

Railsアプリを新規作成してCloud Runサービスにデプロイしてブラウザでアクセスするところまで確認していきます。

## Railsアプリ作成

まずはRailsアプリを作ります。

適当なディレクトリを作ったあと

```shell
mkdir rails-on-cloud-run
cd rails-on-cloud-run
```

`rails`コマンドをセットアップしてから

```shell
bundle init && bundle add rails --skip-install && bundle install --path=.bundle -j4
```

`rails new`を実行します。

```shell
bundle exec rails new . -f
```

今回はデプロイ手順の確認が目的なので、設定は無指定でデフォルトのままにしています。

:::note
Railsアプリを作るときに個人的にいつも使ってるワンライナーです。
いろんなやり方があると思いますが、依存gemを含めてディレクトリ内で完結させたいのでこんなふうにしています。

参考: [Railsアプリを作るときにいつも叩いてるコマンド | oknm.jp](https://oknm.jp/posts/76a6c160baf571683cc48cdaa45705ff27fdfa96)
:::


## Cloud Runのホストをアクセス許可

Cloud Runのホスト名をホワイトリストに追加します。

```diff_ruby:config/environments/production.rb
   # Enable DNS rebinding protection and other `Host` header attacks.
   # config.hosts = [
   #   "example.com",     # Allow requests from example.com
   #   /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
   # ]
+  config.hosts = [
+    /.*\.run\.app/
+  ]
 end
```

:::note
意図しないホスト名によるリクエストを弾くため、ホスト名を明示的に指定する必要があります。

参考: [Rails アプリケーションの設定項目 - Railsガイド](https://railsguides.jp/configuring.html#actiondispatch-hostauthorization)
:::

:::note
Cloud RunサービスのURLは`.run.app`のドメインになります。

参考: [HTTPS リクエストによる呼び出し  |  Cloud Run のドキュメント  |  Google Cloud](https://cloud.google.com/run/docs/triggering/https-request?hl=ja#:~:text=Cloud%20Run%20%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%20URL%20%E3%81%AF%E3%80%81https%3A//%5BTAG%2D%2D%2D%5DSERVICE_IDENTIFIER.run.app%20%E3%81%AE%E5%BD%A2%E5%BC%8F%E3%81%A7%E3%81%99%E3%80%82)
:::

## トップページを設定

いまのままだと表示するページがなくてアクセスするとエラーになってしまうので、ページを追加します。
なんでもいいですが、ここではお手軽にRailsのWelcomeページを設定しておきます。

```diff_ruby:config/routes.rb
 Rails.application.routes.draw do
   # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

   # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
   # Can be used by load balancers and uptime monitors to verify that the app is live.
   get "up" => "rails/health#show", as: :rails_health_check


   # Defines the root path route ("/")
   # root "posts#index"
+  root "rails/welcome#index"
 end
```

:::note
RailsのWelcomeページはproductionでは表示されないので、明示的にルーティングに追加する必要があります。

参考: [Railsの開発用Welcome画面をproductionでも出す #Rails - Qiita](https://qiita.com/udzura/items/5fba78f05c2884163d4f)
:::

## Cloud Runサービスにデプロイ

ここまででアプリの設定は完了しました。

次は`gcloud run deploy`でCloud Runサービスにデプロイします。

```shell
gcloud run deploy rails-on-cloud-run \
    --source . \
    --project advent-calendar-2023 \
    --region asia-northeast1 \
    --allow-unauthenticated \
    --set-env-vars RAILS_MASTER_KEY=$(cat config/master.key)
```

初めて実行したときはAPIの有効化などの質問が出るので、内容を確認しつつ回答していきます。

実行完了まで数分かかるのでしばらく待ちます。正常に完了すると実行結果の最後に作成されたCloud RunサービスのService URLが出力されているはずです。そのURLにブラウザでアクセスするといつものRailsのWelcomeページが表示されます。

![rails_welcome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461/f25137a2-e5c4-518e-1e8e-9da7d989bd9d.png)

以上でRailsアプリをCloud Runにデプロイできました。

:::note
`gcloud run deploy SERVICE --source .`でソースコードからCloud Runサービスにデプロイします。
このコマンドを実行すると、Cloud Buildによるコンテナイメージのビルド、Artifact Registryへのコンテナイメージのpush、そのコンテナイメージを使ってCloud Runサービスを作成・デプロイ、といった一連の作業が自動的に行われます。

参考: [ソースコードからのデプロイ  |  Cloud Run のドキュメント  |  Google Cloud](https://cloud.google.com/run/docs/deploying-source-code?hl=ja)
:::

:::note
コンテナの`RAILS_MASTER_KEY`環境変数に`config/master.key`の内容を設定しておきます。
`RAILS_MASTER_KEY`環境変数もしくは`config/master.key`は`config/credentials.yml.enc`の複号化に必要になります。
`config/credentials.yml.enc`には`secret_key_base`の値が記載されており、`secret_key_base`が見つからないと次のようなエラーでアプリの起動に失敗します。
```
/usr/local/bundle/ruby/3.2.0/gems/railties-7.1.2/lib/rails/application.rb:655:in `validate_secret_key_base': Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit` (ArgumentError)
```

参考: [Rails セキュリティガイド - Railsガイド](https://railsguides.jp/security.html?_fsi=2GFDtrE1&_fsi=2GFDtrE1#%E7%8B%AC%E8%87%AA%E3%81%AEcredential)
:::

:::note
`secret_key_base`の設定は、`config/credentials.yml.enc`のほかにも`SECRET_KEY_BASE`環境変数などいくつかの方法があります。

参考: [secret_key_baseがどういうふうに扱われているか | oknm.jp](https://oknm.jp/posts/9e030108704dc3d1e36743051934126c52ae2e2d)
:::

## 備考: リクエストを待ち受けるポートは自動設定される

Cloud Runサービスのコンテナは`PORT`環境変数で定義されたポートでリクエストを待ち受けるようにする必要があります。
参考: [コンテナを構成する  |  Cloud Run のドキュメント  |  Google Cloud](https://cloud.google.com/run/docs/configuring/containers?hl=ja)

Cloud Runサービスのリビジョンで設定したコンテナポートが`PORT`環境変数に設定されます。リビジョンでコンテナポートを特に指定しなければデフォルト値が設定されます。

Railsは`PORT`環境変数が定義されていればそれを参照します。

https://github.com/rails/rails/blob/main/railties/lib/rails/commands/server/server_command.rb#L214

```rb:railties/lib/rails/commands/server/server_command.rb
        def port
          options[:port] || ENV.fetch("PORT", DEFAULT_PORT).to_i
        end
```

なのでCloud Runサービスにデプロイするときは、とくになにもしなくても自動的にリビジョンで指定されたコンテナポートでRailsアプリがリクエストを待ち受けてくれます。



# まとめ

Cloud Runへのデプロイ手順をまとめました。
今回手順をまとめてみて、ひと昔前にCloud Runを触り始めたときに比べてデプロイが格段に楽になったと感じました。
Rails 7.1から`rails new`で`Dockerfile`が生成されるようになったのと、Cloud Runのソースデプロイが可能になったのが大きいです。
どちらも実サービスを構築するときはそれなりにカスタマイズすることになると思いますが、今回のようにとりあえずアプリをデプロイしてみたいときにはとても助かりました。