# Cloud Run トラブルシュート大全：起動失敗・503/504・OOM(exit 137)・冷起動・デプロイ失敗の原因と直し方

> Cloud Runの本番でよく出るエラーを、公式の正確なメッセージとともに原因別に直す実践ガイド。『Container failed to start and listen on the port defined by the PORT environment variable』、メモリ超過によるexit 137(OOM)、503『no available instance』、504リクエストタイムアウト、イメージpull権限エラー、冷起動の遅さまでを、診断手順とgcloud・コードの修正例で解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: GCP, Cloud Run, トラブルシューティング, 可観測性, サーバーレス, パフォーマンス, 信頼性, インフラ
- URL: https://tomodahinata.com/blog/google-cloud-run-troubleshooting-container-failed-to-start-cold-start-timeout-oom-guide
- カテゴリ: Google Cloud Run 本番運用
- 総合ガイド: https://tomodahinata.com/blog/google-cloud-run-production-guide

## 要点

- 最頻出は『Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable.』。原因は$PORTで0.0.0.0待受できていない・64bit Linux向けにビルドされていない・起動時エラーのいずれか
- exit 137は『the container instance was found to be using too much memory and was terminated』＝メモリ超過(OOM)。メモリリーク・割り当て不足・インメモリFSへの書き込みが原因。メモリ増設かリーク修正かログ出力先の見直し
- 503『The request was aborted because there was no available instance』はインスタンス不足・冷起動・プローブ失敗。最大インスタンス増・最小インスタンスで温め・プローブのタイムアウト緩和で対処
- 504『reached the maximum request timeout』は処理がタイムアウト超過か死んだ接続の再利用。タイムアウト延長・接続検証＋リトライ、または長時間処理をJobsへ切り離す
- デプロイ失敗の多くは権限。『Cloud Run Service Agent must have permission to read the image』はサービスエージェントへのArtifact Registry読み取り権限不足。診断はCloud Loggingとローカル再現(docker run -e PORT=8080)が基本

---

Cloud Runのエラーは、メッセージさえ正しく読めれば、原因はほぼ一意に絞れます。逆に言えば、**「なんとなく」で設定をいじると泥沼**にはまります。本記事は、本番で頻出するエラーを**[公式ドキュメント](https://docs.cloud.google.com/run/docs/troubleshooting)の正確なメッセージ**ごとに整理し、原因と直し方を最短で示します。「`cloud run container failed to start` でググって来た」人が、**そのページで解決して帰れる**ことを目指します。

設計段階で踏まないための予防は [Cloud Run 本番運用ガイド](/blog/google-cloud-run-production-guide)、冷起動とコストの最適化は [並行性・課金ガイド](/blog/google-cloud-run-autoscaling-concurrency-billing-cost-optimization-guide) を参照してください。

---

## まず診断：ログとローカル再現の2本立て

個別のエラーに入る前に、**どんな問題でも最初にやる2つ**を決めておきます。

```bash
# 1. リビジョンのログを見る（エラーの一次情報はここ）
gcloud run services logs read api --region asia-northeast1 --limit 100

# 2. ローカルで本番と同じ条件を再現する（PORTを注入して起動するか？）
docker run --rm -e PORT=8080 -p 8080:8080 \
  asia-northeast1-docker.pkg.dev/PROJECT_ID/app/api:TAG
# → http://localhost:8080 に到達できなければ、本番でも起動しない
```

**「ローカルで `-e PORT=8080` を渡して起動するか」**——これだけで起動系エラーの大半は手元で再現・解決できます。Cloud Loggingにはアプリのstdout/stderrがそのまま出るので、構造化ログを吐いていれば原因追跡が速くなります（[可観測性の設計](/blog/google-cloud-run-production-guide)）。

---

## エラー1：Container failed to start（最頻出）

> **`Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable.`**

デプロイ直後に出る最頻出エラー。Cloud Runが「コンテナを起動したが、`$PORT` で待ち受けてくれない」と判断した状態です。

**原因と直し方：**

1. **`0.0.0.0` で `$PORT` を待ち受けていない**（最多）。`localhost`/`127.0.0.1` 固定や、ポートをハードコードしている。

```python
# ✗ 悪い例：127.0.0.1 / ポート固定 → Cloud Runから到達できず起動失敗
uvicorn.run(app, host="127.0.0.1", port=3000)

# ✓ 正しい例：0.0.0.0 で、PORT環境変数を読む
import os
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
```

2. **64bit Linux向けにビルドされていない**。Apple Silicon (arm64) のローカルでビルドしたイメージをそのまま使うと起こりがち。マルチアーキでビルドするか、`--platform linux/amd64` を指定する。

```bash
docker build --platform linux/amd64 -t IMAGE_URL .
```

3. **起動処理そのものが失敗している**（依存サービスへの接続を起動時に待ってタイムアウト、設定不足で例外）。**起動時に重い同期初期化や外部接続をブロッキングで行わない**。ログに例外が出ていないか確認する。起動が本当に遅いなら、[startupプローブ](/blog/google-cloud-run-production-guide)の `failure_threshold × period_seconds` を広げる。

---

## エラー2：メモリ超過 / exit 137（OOM）

> **`... the container instance was found to be using too much memory and was terminated.`**（コンテナの終了コードは **137**）

割り当てメモリを超えてOOM Killされた状態。Cloud Runの**書き込み可能ファイルシステムはインメモリ**で、書いた分がメモリを食う点に注意。

**原因と直し方：**

1. **メモリ割り当て不足** → ピークに合わせて増やす（ただし闇雲に増やすとコスト増。メトリクスで判断）。

```bash
gcloud run services update api --region asia-northeast1 --memory 1Gi
```

2. **インメモリFSへの書き込み**（大きな一時ファイル、ローカルへのログ出力）→ 一時データは小さく保つか、**Cloud Storageへストリーミング**する。ログは**ファイルではなくstdout**へ。

3. **メモリリーク**（接続・バッファの蓄積）→ リークを直す。大きなオブジェクトをリクエスト間で保持していないか確認。

> 私のマルウェアスキャナは、最大10GiBの素材を扱うため**バッファせずストリーミング検査**してメモリ枯渇を回避していました。「全部メモリに載せてから処理する」設計は、サーバーレスでは特に危険です。大きなデータは**流して処理する**。

---

## エラー3：503 Service Unavailable

> **`The request was aborted because there was no available instance.`**

リクエストを捌けるインスタンスが無かった状態。スパイク・冷起動・スケール上限・プローブ失敗が絡みます。

**原因と直し方：**

1. **最大インスタンスが低すぎてスパイクに負けた** → `--max-instances` を上げる。
2. **冷起動が遅く、起動が間に合わない** → `--min-instances 1` 以上で温める、[冷起動対策](/blog/google-cloud-run-autoscaling-concurrency-billing-cost-optimization-guide)（起動CPUブースト・スリムイメージ・gen1）。
3. **並行性が低すぎて必要インスタンスが膨らんだ** → 並行性を見直す（I/Oバウンドなら上げる）。
4. **livenessプローブが厳しすぎてインスタンスが再起動を繰り返す** → プローブのタイムアウト/閾値を緩める、プローブに重い依存チェックを入れない。

```bash
gcloud run services update api --region asia-northeast1 \
  --min-instances 1 --max-instances 20 --cpu-boost
```

---

## エラー4：504 Gateway Timeout

> **`The request has been terminated because it has reached the maximum request timeout.`**

レスポンスが[リクエストタイムアウト](/blog/google-cloud-run-production-guide)（既定300秒・最大60分）内に終わらなかった状態。

**原因と直し方：**

1. **処理が単純に長い** → タイムアウトを延ばす（`--timeout`）。ただし**60分が上限**。

```bash
gcloud run services update api --region asia-northeast1 --timeout 600
```

2. **そもそもHTTPで抱え込むべきでない長時間処理** → **Cloud Run Jobs / Workflows へ切り離す**のが正解（[Jobs/Workflowsガイド](/blog/google-cloud-run-jobs-workflows-batch-async-idempotent-guide)）。タイムアウトを伸ばし続けるのは設計の先送り。
3. **死んだ接続の再利用**（プールが切れたDB/HTTP接続を使い回している）→ 接続の健全性チェックとリトライを入れる。

---

## エラー5：イメージpull / 権限エラー（デプロイ失敗）

> **`... the Google Cloud Run Service Agent must have permission to read the image ...`**

デプロイ時にイメージを読めない＝**権限不足**。コードの問題ではありません。

**原因と直し方：**

- Cloud Run **サービスエージェント**（`service-PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com`）に、イメージのある**Artifact Registryの読み取り権限**を与える。

```bash
gcloud artifacts repositories add-iam-policy-binding app \
  --location asia-northeast1 \
  --member "serviceAccount:service-PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com" \
  --role "roles/artifactregistry.reader"
```

- **イメージが別プロジェクトにある** → そのプロジェクト側で権限を付与。
- **VPC Service Controls** が読み取りを遮断していないか確認。

関連して、デプロイ用SA（CI）の権限不足でデプロイ自体が失敗するケースは [CI/CDガイド](/blog/google-cloud-run-cicd-cloud-build-github-actions-workload-identity-blue-green-canary-guide) を参照（`run.developer`＋AR読み取り＋ランタイムSAへの `serviceAccountUser`）。

---

## エラー6：コンテナのインポート失敗

> **`The service has encountered an error during container import. Resource readiness deadline exceeded.`**

イメージの取り込み段階で失敗。比較的レアですが原因が分かりにくい。

**原因と直し方：**

- **非UTF-8なファイル名**がイメージ内にある → UTF-8でビルドし直す。
- **Windowsイメージの非対応レイヤー（foreign layers）** → `--allow-nondistributable-artifacts` を有効にして再ビルド。
- 基本は**64bit Linuxの素直なイメージ**にする（マルチステージ・distroless等）。

---

## エラー7：冷起動が遅い（エラーではないが体感を壊す）

明示的なエラーは出ないのに「最初の1リクだけ妙に遅い」——スケールトゥゼロからの**冷起動**です。

**診断と対処（軽い順）：**

1. **イメージを小さく**（マルチステージ・distroless/alpine）。pullと展開が速くなる。
2. **起動CPUブースト**（`--cpu-boost`）で初期化を速く。
3. **遅延初期化**：起動時に全部読み込まず、必要時に初期化。**接続はハンドラ外で一度だけ**生成して再利用。
4. **実行環境 gen1**（冷起動が速い）を軽量APIで選ぶ。
5. それでも体感が許容できない経路だけ **`--min-instances 1`** で温める（常時課金とのトレードオフ）。

詳細な原価試算と打ち手は [並行性・オートスケール・コスト最適化ガイド](/blog/google-cloud-run-autoscaling-concurrency-billing-cost-optimization-guide) にまとめています。

---

## 診断早見表

| 症状 / メッセージ | 一次原因 | まず試すこと |
|------------------|---------|------------|
| `failed to start and then listen on the port` | 0.0.0.0/$PORT待受不可・arm64・起動エラー | ローカルで `-e PORT=8080` 再現、`--platform linux/amd64` |
| exit 137 / `too much memory` | OOM（不足・リーク・インメモリFS） | `--memory` 増、ストリーミング化、ログをstdoutへ |
| 503 `no available instance` | 冷起動・スケール上限・プローブ | `--min-instances` `--max-instances` `--cpu-boost`、プローブ緩和 |
| 504 `maximum request timeout` | 処理超過・死接続 | `--timeout`、長時間処理はJobsへ、接続検証 |
| `Service Agent must have permission to read the image` | AR読み取り権限不足 | サービスエージェントに `artifactregistry.reader` |
| `Resource readiness deadline exceeded` | 非UTF-8/foreign layers | UTF-8・64bit Linuxで再ビルド |

---

## 本番投入チェックリスト（予防）

- [ ] ローカルで **`docker run -e PORT=8080`** が起動する
- [ ] イメージは **64bit Linux**（`--platform linux/amd64` かマルチアーキ）
- [ ] 起動時に**重い同期処理・外部接続のブロッキング待ち**をしない
- [ ] 大きなデータは**メモリに載せず流す**（インメモリFSを使い切らない）
- [ ] **min/max instances** とプローブを設定し、503を予防
- [ ] 長時間処理は **Jobs/Workflows** へ（504をタイムアウト延長で誤魔化さない）
- [ ] **構造化ログ**（stdout）で原因追跡を速くする
- [ ] サービスエージェント/デプロイSAの**権限**を事前に確認

---

## まとめ：メッセージを読めば原因は絞れる

Cloud Runのトラブルシュートは、**公式のエラーメッセージを正確に読む**ことが9割です。「起動しない」なら `$PORT`・`0.0.0.0`・アーキテクチャ、「137」ならメモリ、「503」ならスケールと冷起動、「504」なら長時間処理の切り離し、「image permission」なら権限——と、**メッセージから原因へ一意に降りられる**ように設計されています。慌てて設定をいじる前に、ログを読み、ローカルで再現する。それが最短経路です。

予防は設計から：全体は [Cloud Run 本番運用ガイド](/blog/google-cloud-run-production-guide)、コストと冷起動は [並行性・課金ガイド](/blog/google-cloud-run-autoscaling-concurrency-billing-cost-optimization-guide)、長時間処理は [Jobs/Workflowsガイド](/blog/google-cloud-run-jobs-workflows-batch-async-idempotent-guide) へ。本番障害の調査・恒久対策の設計が必要なら、実運用の知見でお手伝いします。
