コンテナをそのまま動かせるサーバーレス
Cloud RunはDockerコンテナをそのままデプロイできるサーバーレスの実行環境です。Next.jsをDockerfileでビルドできる状態にしておけば、アプリ側のコードをCloud Run向けに書き換える必要はほとんどありません。この手引の自前サーバー構成(Next.jsの基礎、Caddyの基礎、デプロイの基礎)とアプリの作り方は共通のまま、公開先だけをマネージドなクラウドに置き換えるイメージです。
Cloud Runには期限のない無料枠がある
Cloud Runの無料枠は、期限も商用利用の制限もなく毎月リセットされます。GitHubリポジトリに変更を送ると、GitHub Actionsからコンテナをビルドし、Cloud Runへデプロイする流れが基本です。デプロイ自体はGitHub Actions側からgcloud run deployを実行する数行のワークフローで済みます。
データベースはCloud SQLとNeon、どちらを選ぶか
Cloud SQLはGoogle Cloudが提供するマネージドPostgreSQL/MySQLですが、Cloud Runと違って期限のない無料枠がありません。新規アカウント向けの無料トライアルやクレジットを使い切った後は、最小構成でも固定費がかかり続けます。
これに対してNeonはサーバーレスのPostgresで、使っていない時間は自動的に計算リソースがゼロへスケールします。個人開発やアクセスが少ない検証段階のサービスであれば、無料枠の範囲内で運用し続けられる場合があります。DrizzleなどのORMと組み合わせる場合は、サーバーレス環境向けのHTTP接続ドライバーを使う必要がある点には注意します。
Cloud Runの「箱」はTerraformで管理する
Cloud Runサービス自体、サービスアカウント、IAM権限、コンテナイメージを置くArtifact Registry、Neonの接続文字列を保管するSecret Managerは、Terraformのgoogleプロバイダーで宣言的に管理できます。実際にアプリのコンテナイメージを差し替えて反映するのはCI(GitHub Actions)の仕事で、Terraformは「サービスの入れ物」がある状態を保証する役割です。
resource "google_artifact_registry_repository" "app" {
location = "asia-northeast1"
repository_id = "my-app"
format = "DOCKER"
}
resource "google_service_account" "run_sa" {
account_id = "my-app-run"
display_name = "Cloud Run runtime SA"
}
resource "google_secret_manager_secret" "database_url" {
secret_id = "my-app-database-url"
replication {
auto {}
}
}
resource "google_cloud_run_v2_service" "app" {
name = "my-app"
location = "asia-northeast1"
template {
service_account = google_service_account.run_sa.email
containers {
image = "asia-northeast1-docker.pkg.dev/PROJECT_ID/my-app/app:latest"
env {
name = "DATABASE_URL"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.database_url.secret_id
version = "latest"
}
}
}
}
scaling {
min_instance_count = 0
max_instance_count = 3
}
}
}
resource "google_cloud_run_v2_service_iam_member" "public" {
name = google_cloud_run_v2_service.app.name
location = google_cloud_run_v2_service.app.location
role = "roles/run.invoker"
member = "allUsers"
}コンテナイメージのタグ(:latestの部分)は、GitHub Actions側がビルドごとに書き換えてgcloud run deployで反映する運用が一般的です。Terraformの適用と、CIによるイメージ差し替えを同じパイプラインに混在させると競合しやすいため、Cloudflare編と同様にジョブを分けておきます。
.tfファイルや状態ファイルに平文で残さないようにします。Terraformのstateファイルは、同じGoogle Cloud上のCloud Storageバケットに置きます。gcsバックエンドはTerraformが標準で対応しているため、Cloudflare編のR2のようなS3互換の読み替えは不要です。
terraform {
backend "gcs" {
bucket = "my-app-tfstate"
prefix = "cloud-run"
}
}バケット自体も、他のリソースと同じくTerraform管理下に置けます(初回のbootstrapだけは手動、もしくは別の最小構成で作成します)。
resource "google_storage_bucket" "tfstate" {
name = "my-app-tfstate"
location = "asia-northeast1"
uniform_bucket_level_access = true
public_access_prevention = "enforced"
versioning {
enabled = true
}
}public_access_prevention = "enforced"でバケットが公開設定されることを構造上防ぎ、versioningを有効にして、state破損時に過去の版へ戻せるようにします。アクセス権限はプロジェクトの編集者権限などを使い回さず、Terraformを実行するサービスアカウントに対して、このバケットへの読み書きだけを個別に付与します。無料枠と制限を先に把握する
- Cloud Runのリクエスト数:月200万リクエストまで無料(商用利用可、期限なし)
- Cloud RunのCPU時間:月24万vCPU秒まで無料
- Cloud Runのメモリ:月45万GiB秒まで無料
- Cloud SQL:期限のない無料枠はなし。最小構成でも固定費が発生
- Neonのストレージ:プロジェクトあたり0.5GBまで無料
- Neonの計算時間:月100CU時間まで無料(プロジェクトは最大100個まで作成可)
Cloud Run側は無料枠だけで長く運用できる設計ですが、DB側は選ぶサービスによって費用の発生タイミングがまったく異なります。
Cloud SQLとNeon、どちらを選ぶか
Cloud Run+Neonが向く
個人開発、検証段階のサービス、データベースも含めてまず無料で始めたい場合。Postgres本来の機能をそのまま使えます。
Cloud Run+Cloud SQLが向く
常時アクセスのある本番サービス、個人情報や認証情報など機密性の高いデータを扱う場合、同一ネットワーク内での閉域接続や他のGoogle Cloudサービスとの統合を重視する場合。
どちらのDBを選んでも、Cloud Run側の認証設定やシークレット管理、GitHub Actionsによるデプロイの考え方は共通です。