Use Cases

Claude Code × GCP Cloud Run 完全ガイド|コンテナをサーバーレスで自動デプロイ

GCP Cloud RunへのデプロイをClaude Codeで爆速化。Dockerfile生成・自動スケーリング設定・CI/CD構築・Secret Manager連携まで、実例コードで完全解説。

「GCPでコンテナを動かしたいけど、ECSより設定項目が多すぎてわからない」——以前の私もそう思っていました。ところが実際にCloud Runを触ってみると、ECSよりはるかに設定がシンプルで驚いたのが正直な感想です。VPC設定なし、タスクロール設計なし、クラスター管理なし。コンテナイメージさえ用意すれば、ほぼそのままHTTPSエンドポイントが立ち上がります。

さらにClaude Codeと組み合わせると、Dockerfileの生成からCloud Build CI/CDパイプラインの構築まで、一連の作業が驚くほど短時間で完了します。この記事では私が実際に試した手順を6ステップで解説します。


Cloud RunがECSより簡単な理由

Cloud Run(クラウドラン)はGCPが提供するフルマネージドのコンテナ実行サービスです。HTTPリクエストを受け取ったときだけコンテナが起動する、いわゆる「リクエスト駆動型サーバーレス」の仕組みを取っています。

ECSとの主な違いを整理するとこうなります。

Cloud Run:
- クラスター管理: 不要
- ネットワーク設定: デフォルトで外部HTTPS公開
- スケーリング: 0台〜Nまで全自動
- 料金: リクエスト処理時間ベース (アイドル時はほぼ無料)

AWS ECS/Fargate:
- クラスター管理: 必要 (Cluster/Service/TaskDef の3層)
- ネットワーク設定: VPC・セキュリティグループ設計が必要
- スケーリング: 最小台数の課金が発生
- 料金: 起動中のタスク時間ベース

API、Webhook受信、バッチ処理、内部マイクロサービスなど、「HTTP で呼ばれる処理」であれば Cloud Run はほぼ最適解です。


Step 1: DockerfileをClaude Codeで自動生成する

まず TypeScript の Node.js API サーバーを例に、本番レベルの Dockerfile を生成します。マルチステージビルドと非rootユーザー設定はセキュリティ要件として必須です。

claude -p "
以下の条件で本番レベルの Dockerfile を生成して。

- アプリ: TypeScript + Express API (ポート8080)
- Node.js バージョン: 22 LTS
- マルチステージビルド (builder → runner)
- 非rootユーザー (node ユーザー) で実行
- .dockerignore も一緒に生成
- Cloud Run 推奨の PORT 環境変数対応
- ヘルスチェック: /health エンドポイント
"

生成されるDockerfile:

# ---- builder ステージ ----
FROM node:22-alpine AS builder
WORKDIR /app

# 依存関係を先にコピーしてキャッシュを活用
COPY package*.json ./
RUN npm ci --only=production=false

COPY tsconfig.json ./
COPY src ./src
RUN npm run build

# ---- runner ステージ ----
FROM node:22-alpine AS runner
WORKDIR /app

# セキュリティ: 非rootユーザーで実行
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 本番依存のみインストール
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# ビルド成果物をコピー
COPY --from=builder /app/dist ./dist

# Cloud Run は PORT 環境変数でポートを渡す
ENV PORT=8080
ENV NODE_ENV=production

# 非rootユーザーに切り替え
USER appuser

EXPOSE 8080
CMD ["node", "dist/index.js"]

生成される.dockerignore:

node_modules
dist
.env
.env.*
*.log
.git
.gitignore
README.md

Step 2: Cloud Runへの初回デプロイ

Dockerfileができたら、Cloud Runへデプロイするコマンドを生成してもらいます。

claude -p "
以下の条件で GCP Cloud Run へのデプロイコマンドを生成して。

- プロジェクトID: my-project-123
- リージョン: asia-northeast1 (東京)
- サービス名: myapp-api
- メモリ: 512Mi
- CPU: 1
- 同時接続数: 80 (concurrency)
- 認証: 未認証リクエストを許可
- 環境変数: NODE_ENV=production
- ポート: 8080
"

生成されるコマンド一式:

# 1. Docker イメージをビルドして Artifact Registry にプッシュ
gcloud auth configure-docker asia-northeast1-docker.pkg.dev

docker build -t asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:v1.0.0 .
docker push asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:v1.0.0

# 2. Cloud Run にデプロイ
gcloud run deploy myapp-api \
  --image asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:v1.0.0 \
  --region asia-northeast1 \
  --platform managed \
  --memory 512Mi \
  --cpu 1 \
  --concurrency 80 \
  --allow-unauthenticated \
  --set-env-vars NODE_ENV=production \
  --port 8080

デプロイ成功後、https://myapp-api-xxxx-an.a.run.app のようなURLが発行されます。


Step 3: 自動スケーリングを適切に設定する

Cloud Runのデフォルト設定のまま使うと、急激なトラフィックでインスタンスが爆発したり、コールドスタートが頻発したりします。本番では以下の設定が重要です。

claude -p "
Cloud Run のスケーリング設定を最適化して。

要件:
- 夜間はほぼトラフィックなし (コスト削減優先)
- 平常時: 1〜3インスタンス
- ピーク時: 最大20インスタンスまでスケールアウト
- CPU使用率70%を超えたらスケールアウト開始
- コールドスタートを最小限に抑えたい
- 1インスタンスあたりの最大同時接続数: 80
"

生成されるコマンド:

gcloud run services update myapp-api \
  --region asia-northeast1 \
  --min-instances 1 \
  --max-instances 20 \
  --concurrency 80 \
  --cpu-throttling \
  --execution-environment gen2

TypeScriptでのCPUベーススケーリング設定 (clouddeploy.yaml):

# service.yaml - Cloud Run サービス設定ファイル
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: myapp-api
  annotations:
    run.googleapis.com/launch-stage: GA
spec:
  template:
    metadata:
      annotations:
        # 最小インスタンス数 (コールドスタート対策)
        autoscaling.knative.dev/minScale: "1"
        # 最大インスタンス数 (コスト上限)
        autoscaling.knative.dev/maxScale: "20"
        # CPU使用率70%でスケールアウト
        autoscaling.knative.dev/target-utilization-percentage: "70"
        # 第2世代実行環境 (パフォーマンス向上)
        run.googleapis.com/execution-environment: gen2
    spec:
      containerConcurrency: 80
      containers:
        - image: asia-northeast1-docker.pkg.dev/my-project-123/myapp/api:latest
          resources:
            limits:
              memory: 512Mi
              cpu: "1"

Step 4: Secret Managerで環境変数を安全に管理

データベースのパスワードやAPIキーを環境変数に直書きするのは絶対NGです。GCP Secret Managerと連携することで、機密情報を安全に管理できます。

claude -p "
GCP Secret Manager と Cloud Run を連携させるコードと設定を生成して。

- シークレット: DATABASE_URL, SENDGRID_API_KEY, JWT_SECRET
- Cloud Run サービスアカウントに読み取り権限を付与
- TypeScript のアプリ側でシークレットを読み込むコード
- gcloud コマンドも含めて
"

生成される設定:

# シークレットを登録
echo -n "postgresql://user:password@host:5432/db" | \
  gcloud secrets create DATABASE_URL --data-file=-

echo -n "SG.xxxxxxxxxxxx" | \
  gcloud secrets create SENDGRID_API_KEY --data-file=-

echo -n "your-jwt-secret-here" | \
  gcloud secrets create JWT_SECRET --data-file=-

# サービスアカウントに読み取り権限を付与
gcloud projects add-iam-policy-binding my-project-123 \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

# Cloud Run にシークレットをマウント
gcloud run services update myapp-api \
  --region asia-northeast1 \
  --set-secrets="DATABASE_URL=DATABASE_URL:latest,SENDGRID_API_KEY=SENDGRID_API_KEY:latest,JWT_SECRET=JWT_SECRET:latest"

TypeScriptアプリ側での読み込みコード (src/config.ts):

// src/config.ts
// Cloud Run では環境変数として自動注入されるので
// process.env でそのまま読み込める
export const config = {
  databaseUrl: process.env.DATABASE_URL!,
  sendgridApiKey: process.env.SENDGRID_API_KEY!,
  jwtSecret: process.env.JWT_SECRET!,
  port: parseInt(process.env.PORT || "8080", 10),
  nodeEnv: process.env.NODE_ENV || "development",
};

// 起動時にシークレットが揃っているか検証
const requiredEnvVars = ["DATABASE_URL", "SENDGRID_API_KEY", "JWT_SECRET"];
for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    console.error(`Missing required environment variable: ${envVar}`);
    process.exit(1);
  }
}

Step 5: Cloud BuildでCI/CDパイプラインを構築

毎回手動でビルド・デプロイするのは非効率です。Cloud Build + GitHubの連携で、main ブランチへのpushと同時に自動デプロイが走るようにします。

claude -p "
GitHub → Cloud Build → Cloud Run の CI/CDパイプラインを設定して。

要件:
- main ブランチへの push でトリガー
- テスト実行 → Dockerイメージビルド → Artifact Registryプッシュ → Cloud Runデプロイ
- デプロイ失敗時はSlack通知
- cloudbuild.yaml を生成して
"

生成される cloudbuild.yaml:

# cloudbuild.yaml
steps:
  # Step 1: 依存関係のインストールとテスト
  - name: "node:22-alpine"
    id: "test"
    entrypoint: "sh"
    args:
      - "-c"
      - |
        npm ci
        npm run test
        npm run lint

  # Step 2: Dockerイメージのビルド
  - name: "gcr.io/cloud-builders/docker"
    id: "build"
    args:
      - "build"
      - "-t"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:$COMMIT_SHA"
      - "-t"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:latest"
      - "."

  # Step 3: Artifact Registry へプッシュ
  - name: "gcr.io/cloud-builders/docker"
    id: "push"
    args:
      - "push"
      - "--all-tags"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api"

  # Step 4: Cloud Run へデプロイ
  - name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
    id: "deploy"
    entrypoint: "gcloud"
    args:
      - "run"
      - "deploy"
      - "myapp-api"
      - "--image"
      - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:$COMMIT_SHA"
      - "--region"
      - "asia-northeast1"
      - "--platform"
      - "managed"
      - "--quiet"

  # Step 5: Slack通知 (成功時)
  - name: "curlimages/curl"
    id: "notify-success"
    entrypoint: "curl"
    args:
      - "-X"
      - "POST"
      - "-H"
      - "Content-type: application/json"
      - "--data"
      - '{"text":"✅ Cloud Run デプロイ完了: $COMMIT_SHA"}'
      - "$_SLACK_WEBHOOK_URL"

images:
  - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:$COMMIT_SHA"
  - "asia-northeast1-docker.pkg.dev/$PROJECT_ID/myapp/api:latest"

options:
  logging: CLOUD_LOGGING_ONLY
  machineType: E2_HIGHCPU_8

timeout: "1200s"

Step 6: カスタムドメイン設定とロードバランサー

Cloud Runが発行するデフォルトURLではなく、独自ドメインを設定するにはGCPのロードバランサー経由が推奨です。

claude -p "
Cloud Run にカスタムドメイン api.example.com を設定する手順と
Terraform コードを生成して。

- SSL証明書は Google マネージド
- Cloud Armor でDDoS保護
- ロードバランサー経由でCloud Runにルーティング
"

生成される Terraform コード (main.tf):

# main.tf - Cloud Run + Load Balancer + SSL

# Cloud Run サービスのバックエンド
resource "google_compute_region_network_endpoint_group" "cloudrun_neg" {
  name                  = "myapp-neg"
  network_endpoint_type = "SERVERLESS"
  region                = "asia-northeast1"

  cloud_run {
    service = "myapp-api"
  }
}

# バックエンドサービス
resource "google_compute_backend_service" "default" {
  name     = "myapp-backend"
  protocol = "HTTP"

  backend {
    group = google_compute_region_network_endpoint_group.cloudrun_neg.id
  }

  # Cloud Armor セキュリティポリシー
  security_policy = google_compute_security_policy.policy.id
}

# Google マネージドSSL証明書
resource "google_compute_managed_ssl_certificate" "default" {
  name = "myapp-ssl-cert"
  managed {
    domains = ["api.example.com"]
  }
}

# HTTPS ロードバランサー
resource "google_compute_url_map" "default" {
  name            = "myapp-url-map"
  default_service = google_compute_backend_service.default.id
}

resource "google_compute_target_https_proxy" "default" {
  name             = "myapp-https-proxy"
  url_map          = google_compute_url_map.default.id
  ssl_certificates = [google_compute_managed_ssl_certificate.default.id]
}

resource "google_compute_global_forwarding_rule" "https" {
  name       = "myapp-https-forwarding-rule"
  target     = google_compute_target_https_proxy.default.id
  port_range = "443"
  ip_address = google_compute_global_address.default.address
}

# Cloud Armor DDoS保護ポリシー
resource "google_compute_security_policy" "policy" {
  name = "myapp-security-policy"

  rule {
    action   = "deny(403)"
    priority = "1000"
    match {
      expr {
        expression = "evaluatePreconfiguredExpr('sqli-stable')"
      }
    }
    description = "SQLインジェクション対策"
  }

  rule {
    action   = "allow"
    priority = "2147483647"
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["*"]
      }
    }
    description = "デフォルト許可"
  }
}

落とし穴5選

1. コールドスタートでタイムアウトする

Cloud Runはリクエストがない時間が続くとインスタンスを0台に落とします(最小インスタンス数が0の場合)。次のリクエスト受信時にコンテナ起動から始まるため、1〜2秒の遅延が発生します。本番ではmin-instancesを1以上に設定してください。

# コールドスタート対策: 最小1インスタンスを常時起動
gcloud run services update myapp-api \
  --min-instances 1 \
  --region asia-northeast1

2. SIGTERM ハンドリングを忘れる

Cloud Runはスケールインやデプロイ時にSIGTERMシグナルを送ります。適切に処理しないと、処理中のリクエストが強制終了されます。

// src/index.ts - SIGTERMを適切に処理する
import express from "express";
const app = express();
const server = app.listen(process.env.PORT || 8080);

// グレースフルシャットダウン
process.on("SIGTERM", () => {
  console.log("SIGTERM received. Graceful shutdown started.");
  server.close(() => {
    console.log("HTTP server closed.");
    process.exit(0);
  });

  // 30秒以内に終了しなければ強制終了
  setTimeout(() => {
    console.error("Forced shutdown after timeout.");
    process.exit(1);
  }, 30000);
});

3. 機密情報を環境変数に直書きする

# ❌ 絶対NG: シークレットを直書き
gcloud run services update myapp-api \
  --set-env-vars DATABASE_PASSWORD=mypassword123

# ✅ 正解: Secret Manager 経由で安全に渡す
gcloud run services update myapp-api \
  --set-secrets="DATABASE_PASSWORD=DATABASE_PASSWORD:latest"

4. メモリ設定が不足する

Node.jsはデフォルトでヒープサイズが小さいです。512MiのコンテナにNode.jsを動かすと、大きいデータを処理する際にOOM(Out of Memory)で落ちることがあります。

# メモリ不足対策: Node.js のヒープサイズを明示
CMD ["node", "--max-old-space-size=384", "dist/index.js"]

5. リクエスト外のバックグラウンド処理をしない

Cloud Runはリクエストを処理していない間、CPUが実質使えない状態になります(CPU throttling)。定期的なバックグラウンド処理が必要な場合はCloud Schedulerと組み合わせるか、常時起動モードを使ってください。

# 常時CPUを割り当てるモード (バックグラウンド処理が必要な場合)
gcloud run services update myapp-api \
  --no-cpu-throttling \
  --region asia-northeast1

まとめ

タスクClaude Code の貢献
Dockerfile 生成マルチステージビルド・非rootユーザー設定を自動化
初回デプロイgcloud コマンド一式を要件から生成
スケーリング設定min/max インスタンス・CPU閾値を最適化
Secret Manager 連携シークレット登録・権限付与・マウント設定を生成
CI/CD パイプラインcloudbuild.yaml をテスト込みで生成
カスタムドメインTerraform でロードバランサー構成を自動生成

ECSと比べてCloud Runは「動かすだけ」なら圧倒的にシンプルです。Claude Codeと組み合わせると、Dockerfileの生成からCI/CDパイプライン構築まで1時間以内に完了します。まずStep1〜3だけ試して、Cloud Runの快適さを体感してみてください。

関連記事

参考資料

#claude-code #gcp #cloud-run #docker #typescript #serverless
無料プレゼント

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。