💰 FinOps とコスト最適化徹底深掘り
Spot VM / CUD / SUD / Recommender / 各ワークロード最適化を、計算式・割引率・事故ケース・実務 BP まで深掘り。FinOps の Inform → Optimize → Operate サイクルで体系化。
- 観測可能性のオーバー ingestion:log/metrics の exclusion 漏れで月数十万円が一瞬で消える
- Cloud Run min-instances を盲目的に >0 設定:cold start を恐れて常時課金
- Egress (cross-region/Internet):multi-region サービスで Premium Tier 想定外
- Idle resource 放置:unattached PD / static IP / 古い snapshot
- CUD の塩漬け:3 年 commitment 後にワークロード消失
- GKE Autopilot を「軽量 Pod」で多用:per-Pod 料金で Standard より割高に
1. FinOps の哲学とサイクル
FinOps は FinOps Foundation が提唱する「クラウドのコストを エンジニア・財務・経営 の三位一体で継続最適化する」運営フレームワーク。Inform → Optimize → Operate の 3 フェーズを反復する。
📖 Google 公式:Cost optimization pillar — Google Cloud Architecture Framework
1.1 ShowBack vs ChargeBack
| 方式 | 説明 | 強み | 弱み |
|---|---|---|---|
| ShowBack | 部門別にコストを表示するだけ、実際の支払いは中央集約 | 導入が容易・チーム間摩擦が少ない | 削減インセンティブが弱い |
| ChargeBack | 部門予算から実費請求 | 強い削減インセンティブ・予算規律 | 正確なタグ付け必須・組織内政治 |
| ハイブリッド | 共通基盤は ShowBack、ワークロードは ChargeBack | 現実解 | 境界設計が複雑 |
1.2 Billing Export と Unit Economics
BigQuery Billing Export(Standard / Detailed / Pricing)を設定し、Looker Studio で可視化するのが Google 推奨パス。
-- Detailed Billing Export からチーム別コスト集計
SELECT
invoice.month,
labels.value AS team,
SUM(cost) - SUM(IFNULL((SELECT SUM(amount) FROM UNNEST(credits)), 0)) AS net_cost
FROM `billing_project.billing_export.gcp_billing_export_resource_v1_XXXXXX`
CROSS JOIN UNNEST(labels) AS labels
WHERE labels.key = 'team'
AND DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY 1, 2
ORDER BY 1 DESC, net_cost DESC;
Unit Economics:リクエスト 1 件あたりのコスト、ユーザ MAU あたりのコストを定義し、スケールしたときの収益性を予測。SaaS では必須指標。
1.3 GKE Cost Allocation
GKE クラスタで --enable-cost-allocation を有効化すると、Namespace / Workload 単位の CPU/Memory 使用量を Billing Export に注入してくれる。
gcloud container clusters update CLUSTER_NAME \
--enable-cost-allocation \
--location=REGION
📖 公式:View cluster cost allocation data — GKE Docs
1.4 Budget Alert の正しい設計
# Budget の threshold rules 例(gcloud or Terraform)
budget_filter:
projects: ["projects/PROD_PROJECT"]
amount:
specified_amount:
currency_code: JPY
units: 5000000 # 月 500 万円
threshold_rules:
- threshold_percent: 0.5
- threshold_percent: 0.75
- threshold_percent: 0.9
- threshold_percent: 1.0
- threshold_percent: 1.0
spend_basis: FORECASTED_SPEND # 予測ベース
spend_basis: FORECASTED_SPEND を 1 つは必ず追加。
2. Spot VM 徹底解剖
📖 公式:Spot VMs — Compute Engine Docs
2.1 Spot VM ライフサイクル
2.2 Spot VM vs Preemptible(廃止予定)
| 項目 | Spot VM | Preemptible VM(旧仕様、新規非推奨) |
|---|---|---|
| 最大稼働時間 | 制限なし | 24 時間で必ず終了 |
| 割引率 | 最大 91%(変動) | 固定 80% |
| 料金更新 | 動的(リージョン需給) | 固定 |
| preemption 通知 | 30 秒前 ACPI G2 | 30 秒前 ACPI G2 |
| Termination action | STOP or DELETE 選択可 | 常に DELETE |
| GPU/TPU | 対応 | 対応 |
| CUD/SUD 適用 | 不可 | 不可 |
新規ワークロードは Spot 一択。Preemptible はレガシー互換目的で残存。
2.3 30 秒 grace period のハンドリング
#!/bin/bash
# /etc/preempt-shutdown.sh
# Spot preemption 通知を受け取った時の優雅な停止
# 1) アプリに SIGTERM 送出(10 秒以内)
systemctl stop my-worker
# 2) 進行中バッチを cancel API で外部に通知(5 秒以内)
curl -X POST https://api.example.com/cancel \
-H "Authorization: Bearer $TOKEN" \
--max-time 5
# 3) ローカル WAL を GCS にアップロード(残り 10 秒)
gsutil -q cp /var/lib/myapp/wal-* gs://drain-bucket/$(hostname)/
# 4) sync して終了
sync
shutdown script は --metadata shutdown-script=... または --metadata-from-file shutdown-script=... で設定。Cloud Logging には自動転送される。
2.4 GKE Spot ノードプール
gcloud container node-pools create spot-workers \
--cluster=my-cluster \
--location=asia-northeast1 \
--spot \
--enable-autoscaling --min-nodes=0 --max-nodes=100 \
--machine-type=n2-standard-8 \
--node-taints=cloud.google.com/gke-spot=true:NoSchedule
Pod 側で toleration と nodeSelector を指定:
spec:
tolerations:
- key: cloud.google.com/gke-spot
operator: Equal
value: "true"
effect: NoSchedule
nodeSelector:
cloud.google.com/gke-spot: "true"
terminationGracePeriodSeconds: 25 # 30 秒以内に終了完了
2.5 ハイブリッド node pool 設計
--autoscaling-profile=optimize-utilization に設定。Pod 配置を高密度に詰め、不要 node を素早く削除。デフォルトは balanced(中断耐性重視)。
2.6 Spot で動かしてよい / ダメ
| カテゴリ | 適 | 不適 |
|---|---|---|
| 計算特性 | Stateless / batch / 並列可 | Stateful / シングルトン / 中断回復難 |
| 具体例 ✓ | ML training, video transcoding, CI/CD runner, web 後段の worker, Spark/Dataflow worker | |
| 具体例 ✗ | DB primary, Redis, queue broker (Kafka leader), gateway/edge LB |
2.7 Spot 事故ケース
minAvailable: 50% 等)。
terminationGracePeriodSeconds は 25-28 秒 に。
3. CUD(Committed Use Discounts)完全理解
📖 公式:Committed use discounts — Compute Engine Docs
3.1 CUD の 2 種類
| Resource-based CUD | Spend-based CUD(Flexible CUD) | |
|---|---|---|
| 対象 | vCPU / Memory / GPU を 個別に commit | 金額($/時)を commit、対象サービスを横断適用 |
| 柔軟性 | 低(マシンファミリー固定) | 高(同サービス内で自由) |
| 割引率 | 1y: ~28-37% / 3y: ~46-66% | 1y: ~28% / 3y: ~46%(やや低い) |
| 対応サービス | GCE, GKE node, Cloud SQL, Spanner | GCE, Cloud Run, GKE Autopilot, Cloud SQL, Spanner, AlloyDB, Dataflow, Memorystore など多数 |
| 変更可否 | cancel 不可 | cancel 不可 |
3.2 割引率の具体値(リージョン・マシンファミリー別)
| マシンファミリー | 1y vCPU | 1y RAM | 3y vCPU | 3y RAM |
|---|---|---|---|---|
| N1 | ~37% | ~37% | ~57% | ~57% |
| N2 / N2D | ~37% | ~37% | ~55% | ~55% |
| E2 | ~28% | ~28% | ~46% | ~46% |
| C2 / C2D | ~37% | ~37% | ~55% | ~55% |
| M1 / M2 (mem-optimized) | ~25% | ~25% | ~52% | ~52% |
| A2 (GPU) | ~30-40% | ~30-40% | ~50-66% | ~50-66% |
3.3 CUD 自動適用の階層
3.4 CUD Recommender
Recommender API は過去 30 日の使用量を分析し、購入推奨 CUD を提示。Console から確認可能。
gcloud recommender recommendations list \
--project=$PROJECT_ID \
--location=global \
--recommender=google.compute.commitment.UsageCommitmentRecommender
3.5 CUD 購入タイミング戦略
- 0-3 ヶ月:観察期間。Recommender が安定する 30 日以上を待つ
- 3-6 ヶ月:1 年 Resource CUD を base load の 50-70% で購入(保守的)
- 6-12 ヶ月:使用率が安定したら追加で 80-90% まで Resource CUD
- 12 ヶ月以降:3 年 CUD で base の 50% を固定(割引率最大化)
- 残り peak は Spend-based CUD(Flexible)+ Spot で吸収
3.6 CUD 事故ケース
4. SUD(Sustained Use Discounts)詳細
📖 公式:Sustained use discounts — Compute Engine Docs
4.1 SUD の自動適用条件
SUD は 申請不要・自動適用。月間で N1/N2/N2D/E2/C2/M1 の vCPU と RAM を一定割合以上稼働した分について段階的に割引。
| 月稼働率 | 適用される割引率(on-demand 価格に対し) |
|---|---|
| 0% - 25% | 0%(フル価格) |
| 25% - 50% | 20% 割引 |
| 50% - 75% | 40% 割引 |
| 75% - 100% | 60% 割引 |
| 月全体平均 | 最大 30% 程度の実効割引(24/7 稼働の場合) |
※ N1 と他の 2nd-gen 系で正確な階段の刻みが異なる。最新の数値は公式 docsで確認。
4.2 inferred instance(推論インスタンス)
SUD は個別 VM の稼働時間ではなく、同マシンタイプの合計 vCPU・メモリ時間 を合算した「推論インスタンス」単位で計算する。
・vCPU 時間 = 4 vCPU × 8h × 30 日 × 90 台 = 86,400 vCPU-h
・1 つの n2-standard-4 が 1 ヶ月フル稼働 = 4 × 730 = 2,920 vCPU-h
・推論インスタンス数 = 86,400 / 2,920 ≈ 29.6 台分
→ これら 29.6 台分が 24/7 稼働したものとして SUD が階段適用される。
4.3 CUD との併用ロジック
CUD と SUD は重複ではなく順次適用。CUD を多く購入していれば SUD の効きどころは限定的。
4.4 SUD 事故ケース
5. Network Tiers と Egress コスト
📖 公式:Network Service Tiers overview
5.1 Premium Tier vs Standard Tier
| 項目 | Premium Tier | Standard Tier |
|---|---|---|
| 経路 | Google global backbone(送信元から目的地まで Google ネットワーク内) | ISP 経由(出口リージョンの ISP に渡す) |
| SLA | 99.99% global IP | 99.9% regional IP |
| LB | Global LB / Premium GLB 利用可 | Regional LB のみ |
| Cloud CDN | 使える | 使えない |
| 料金 | 高い(特に大陸間 egress) | 安い(~40-60% 安) |
| 推奨用途 | グローバル SaaS / 低レイテンシ / 重要本番 | region 内ユーザ / バッチ転送 / 内部システム |
5.2 Egress 料金体系
| 方向 | 料金/GB(目安) |
|---|---|
| 同ゾーン内 | 無料 |
| 同リージョン別ゾーン | $0.01 |
| 同大陸別リージョン | $0.02 |
| 大陸間(asia → us) | $0.08 |
| インターネット(Premium) | $0.12 - $0.23 |
| インターネット(Standard) | $0.05 - $0.09 |
| Cloud CDN cache fill | $0.01 - $0.04 |
5.3 Cross-Cloud Interconnect
AWS / Azure / OCI / Alibaba との専用線接続。Egress は Cross-Cloud Interconnect 料金(公衆インターネット egress より安い)。
5.4 Network Tier 事故ケース
6. Recommender / Active Assist
📖 公式:Recommender overview
6.1 Active Assist 全体像
6.2 Recommender 5 カテゴリ詳細
| カテゴリ | 主な Recommender ID | 提案内容 |
|---|---|---|
| Cost |
google.compute.instance.MachineTypeRecommendergoogle.compute.instance.IdleResourceRecommendergoogle.compute.disk.IdleResourceRecommendergoogle.compute.commitment.UsageCommitmentRecommendergoogle.iam.policy.Recommender
|
VM rightsizing / Idle VM / Idle PD / CUD 購入 / IAM role 縮小 |
| Security | google.compute.firewall.Recommendergoogle.iam.policy.Recommender |
不要な FW rule / 過剰権限 IAM 削減 |
| Performance | google.compute.instance.MachineTypeRecommender |
サチっている VM の machine type up |
| Manageability | Cloud Asset / Deprecated API insight | 未使用 project / 廃止予定 API 利用検知 |
| Reliability | Reliability Insights / Cloud Asset | SPOF / quota 枯渇予測 |
6.3 Recommender 自動化(GitOps PR 生成パターン)
# Recommender 取得例
gcloud recommender recommendations list \
--project=$PROJECT_ID \
--location=global \
--recommender=google.compute.instance.MachineTypeRecommender \
--format=json
6.4 Recommender 事故ケース
7. ワークロード別コスト最適化
7.1 GKE 最適化
| 項目 | Standard | Autopilot |
|---|---|---|
| 料金モデル | node 料金(GCE 価格 + 管理費) | Pod 単位(vCPU/Memory request × 時間) |
| 得意な workload | 大量・密度の高い Pod | 個数少 / リソース大の Pod |
| Spot 対応 | node pool として Spot 構成可 | Spot Pod として指定可(nodeSelector: cloud.google.com/gke-spot) |
| 運用負担 | node 管理あり | node 隠蔽、ほぼゼロ |
・Autopilot: 10 vCPU × $0.0445/h + 20 GiB × $0.0049/h × 730h ≈ 月 $396(Pod request ベース)
・Standard: n2-standard-16(16 vCPU / 64 GiB)× 1 台 × $0.7763/h × 730h ≈ 月 $566(node 単位 + 管理費別)
→ 軽量・少数 Pod なら Autopilot 有利。ただし bin packing で詰められるなら Standard。
Bin Packing 最適化:CA の --autoscaling-profile=optimize-utilization + Pod の reasonable な requests 設定で、node 利用率を 80%+ まで上げる。
7.2 Cloud Run 最適化
| 設定 | コスト影響 | 推奨 |
|---|---|---|
min-instances | 0 なら scale to zero(cold start 数百ms-数秒)、>0 なら常時課金 | SLO 厳しいなら 1-2、それ以外は 0 |
cpu-always-allocated (旧 CPU always allocated) | OFF なら request 処理中だけ CPU 課金、ON なら常時 | 背景処理あり / WebSocket は ON、stateless API は OFF |
concurrency | 1 → 80 で同 instance あたりの処理数が増え単価激減 | I/O bound なら 80 (max)、CPU bound なら 8-32 |
| CPU boost | 起動時 CPU を倍にし cold start 短縮(Gen2) | cold start 体感する全ケースで ON |
| memory | 不要に大きいと毎リクエスト課金 | Profiler で実測しタイト設定 |
・concurrency=1: 1000 万 × 200ms = 2,000,000 vCPU-sec ≈ 556 vCPU-h × $0.024 = $13.3(vCPU 部分のみ)
・concurrency=80: 同時 80 リクエスト処理で実 vCPU 時間 1/80 ≈ $0.17
→ I/O bound なら concurrency 上げる効果は 10-80 倍
7.3 Compute Engine 最適化
- Right sizing:Recommender + 観測 30 日以上
- Custom machine type:vCPU/RAM 比率を workload に合わせる(GCE のみ、N1/N2 系で利用可)
- Sole-tenant Node:BYOL や license compliance に必要なら(コストは高い)
- PD タイプ選定:
・Standard(HDD):低速・安価、バックアップ向け
・Balanced:SSD でコスト 70%、汎用
・SSD:低レイテンシが必要な DB
・Extreme:> 100K IOPS が必要な特殊用途のみ - Snapshot lifecycle policy:日次 7 days + 週次 4 weeks + 月次 12 months で自動削除
7.4 観測可能性自体のコスト削減
- Log Exclusion filter:不要な severity=INFO ログを除外(最大削減効果)
- Log Sampling:必要だが大量のログを 10% にサンプル
- Log Retention 短縮:_Default bucket を 30 日 → 7 日に
- Metrics ingestion 制限:高基数ラベル抑制
- Trace sampling rate:0.1% に下げる(1% でも大量)
7.5 ワークロード別事故ケース
min-instances=1 + CPU boost、cold start 完全回避不要なら sampling で対処。
8. 事故ケース総集編 / 即答パターン
8.1 全事故ケース一覧(31 件)
| # | 章 | 事故 | 教訓・対処 |
|---|---|---|---|
| 1-1 | FinOps | Budget 絶対値のみ、予測 200% に気づけず | FORECASTED_SPEND threshold 必須 |
| 1-2 | FinOps | Billing Export を本番 project に格納し削除 | 専用 billing project に分離 |
| 2-1 | Spot | 本番 DB を Spot で動かしデータロスト | stateful は Spot 禁止 |
| 2-2 | Spot | PDB なしで GKE Spot 一斉再起動 | PDB minAvailable: 50%+ |
| 2-3 | Spot | terminationGracePeriodSeconds 60 で SIGKILL | 25-28 秒に設定 |
| 2-4 | Spot | リージョン Spot capacity 枯渇 | multi-region/zone 分散 |
| 2-5 | Spot | shutdown script で snapshot 取り損ね | snapshot schedule で別途実行 |
| 2-6 | Spot | CUD リソースを Spot に置換 | CUD 期間中はリプレースしない |
| 3-1 | CUD | 3 年 CUD 直後に戦略変更で塩漬け | 3y は base load の 50-70% まで |
| 3-2 | CUD | Flexible CUD が別サービスに消費 | Compute 単一なら Resource-based |
| 3-3 | CUD | N1→N2 移行で CUD 無効化 | CUD 購入前にファミリー固定 |
| 3-4 | CUD | 他 project が CUD を食う | sharing 設定確認 |
| 3-5 | CUD | Spot 移行で CUD 余剰 | Spot 導入前に試算 |
| 4-1 | SUD | stop/start で SUD 失うと誤解 | inferred で合算される |
| 4-2 | SUD | マシンファミリー混在で SUD 分散 | ファミリー統一 |
| 5-1 | Egress | multi-region で月 100 万円 egress | cross-region 同期最小化 |
| 5-2 | Egress | GCS multi-region で予期せぬ DL 料金 | region/dual-region に変更 |
| 5-3 | Egress | default が Premium で意図せぬ高額 | default を Standard に |
| 5-4 | Egress | Cloud CDN なしで配信 | 静的は CDN 必須 |
| 6-1 | Recommender | Idle VM 自動削除で本番削除 | 削除系は人間レビュー |
| 6-2 | Recommender | rightsizing で性能劣化 | 30 日 + ピーク時間含む |
| 6-3 | Recommender | IAM Recommender で月次 job 失敗 | 長周期 job を観測対象に |
| 7-1 | Cloud Run | min-instances=0 で SLO 違反 | SLO 厳しいなら =1 + CPU boost |
| 7-2 | GKE | Autopilot で DaemonSet コスト | 大量 Pod は Standard |
| 7-3 | GCE | PD SSD 過剰 | IOPS 実測 → Balanced 検討 |
| 7-4 | Logging | Exclusion なしで月 50 万円 | 新サービスは Exclusion 設計 |
| 7-5 | Cloud Run | concurrency=1 で 80 倍コスト | 負荷試験で実測 |
8.2 即答すべき選択肢マトリクス
| 用途・条件 | 推奨コスト最適化テクニック |
|---|---|
| 夜間バッチ(中断許容) | Spot VM + MIG |
| 24/7 安定 base load を 3 年保証可 | 3 年 Resource-based CUD(最大 66% off) |
| 複数サービス横断で柔軟に commit したい | 1-3 年 Spend-based CUD (Flexible CUD) |
| VM が CPU 余り気味 | Recommender (MachineTypeRecommender) |
| 長期保管ログ(読み取り稀) | Log Bucket retention 短縮 + GCS Coldline/Archive sink |
| cold start 許容できる API | Cloud Run min-instances=0 |
| cold start 不許可 API | Cloud Run min-instances=1-2 + CPU boost |
| GKE node pool 利用率向上 | CA optimize-utilization profile + bin packing |
| 軽量 Pod 数個だけ | GKE Autopilot or Cloud Run |
| 大量 Pod / DaemonSet | GKE Standard |
| 内部システムで region 内のみ通信 | Network Tier: Standard |
| グローバル本番 | Network Tier: Premium + Cloud CDN |
| multi-region データ転送大量 | region/dual-region GCS + ユーザ近接配信 |
| BigQuery クエリコスト | Slot reservations (1y/3y) + partitioning + clustering |
| 未使用リソースの掃除 | Recommender + Unattended Project Recommender |
| コスト ChargeBack | Detailed Billing Export + label/tag 必須化 |
| 突発スパイク予防 | Budget Alert (FORECASTED_SPEND) + Quota |
| 観測コスト爆発防止 | Log Exclusion → Sampling → Retention 短縮 |
8.3 Carbon Footprint と Sustainability
Well-Architected の Sustainability 柱に対応。Cloud Carbon Footprint で project / region / service 別の CO₂ 排出量を可視化。
- 低炭素リージョン選定:europe-north1 (Finland), us-central1 (Iowa), europe-west1 (Belgium) など。公式 region carbon data ↗
- Scope 1 / 2 / 3 の区別:GCP の電力使用は Scope 2。GHG プロトコル準拠
- Sustainability vs Cost vs Performance の 3 軸トレードオフ:低炭素リージョンが遠ければレイテンシ悪化
8.4 最終チェックリスト
- Budget Alert(絶対値 + 予測)が全 production project で動いている
- Recommender 推奨を月次でレビュー、PR 化
- BigQuery Billing Export → Looker Studio ダッシュボードで部門別可視化
- label/tag 必須化(team, env, costcenter)が Org Policy で enforce
- CUD の購入率と消化率を四半期レビュー
- Idle VM / Unattached PD / 古い snapshot を月次掃除
- Log Exclusion filter 漏れがないか新サービス追加時にチェック
- Cloud Run concurrency / min-instances 設定が SLO とコストのバランスで最適か
- cross-region egress / Premium Tier の利用が必要最小限か
- Carbon Footprint レポートを年次でステークホルダーに共有
- 「最も低コスト」「最も少ない運用負荷」要件 → Recommender / Active Assist / マネージドサービス選択
- 「中断許容バッチ」→ Spot VM
- 「3 年安定」→ 3 年 Resource-based CUD(最大 66% off)
- 「複数サービス横断」→ Flexible CUD(Spend-based)
- 「観測コスト削減」→ Exclusion → Sampling → Retention 短縮の順
- 「内部のみ通信」→ Network Tier Standard、Cloud CDN は静的のみ
- 「Carbon 配慮」→ 低炭素リージョン選定 + Cloud Carbon Footprint レポート
9. GKE 運用深掘り:事故・コスト・肥大化対策
Section 2 / 7 では Spot や Autopilot vs Standard の入口を扱いましたが、本章では「現場で実際に燃えた事故」「請求書がなぜ跳ねたか」「どう抑え込んだか」に絞り、より実務寄りで深掘りします。事故ケースは Section 2.7 / 7.5 との重複を避け、Control Plane / Autoscaling / Workload Identity / Ingress / Logging など運用層の罠を集めています。
「Autopilot is a mode of operation in GKE in which Google manages your cluster configuration, including your nodes, scaling, security, and other preconfigured settings.」 — GKE Autopilot overview
9.1 重大事故ケース 10 件(実務深掘り版)
各ケースは 症状 / 原因 / 処置 / 教訓 / 検知 metric の 5 行で構成。Section 2 / 7 と重複しないように、Autopilot 制約・Cluster Autoscaler 挙動・Control Plane upgrade・Workload Identity・Ingress Health Check・Logging quota を中心に選定しています。
| 症状 | 監視 agent(Datadog DaemonSet)を Autopilot にデプロイ。Pod ... was rejected by admission webhook: DaemonSet using hostPath is not allowed で全 node に展開されず、host metric が一切収集されない。 |
|---|---|
| 原因 | Autopilot はセキュリティ強化のためのデフォルト制約として、hostPath、hostNetwork、hostPID、特権コンテナ等を禁止。DaemonSet 自体は許可されているが、host リソースへのアクセスを要する DaemonSet は webhook で reject される。 |
| 処置 | ① まず Datadog 等の公式 chart が Autopilot 対応版を提供していないか確認(Datadog は GKE Autopilot 専用 chart あり) → ② 公式対応がない場合、Cloud Operations for GKE(Managed Service for Prometheus、Cloud Logging)に切替 → ③ どうしても hostPath が必要ならStandard 移行を検討。kubectl get pods -n datadog -o yaml | grep "rejected" で原因確認。 |
| 教訓 | Autopilot 採用前に「どんな DaemonSet を使うか」を洗い出し、Autopilot の制約 (許可されないワークロード一覧 ↗) と突き合わせる。セキュリティ・監視・CNI 系の DaemonSet は Autopilot で動かない可能性が高い。 |
| 検知 | Cloud Logging で resource.type="k8s_cluster" + protoPayload.response.reason="Forbidden" + protoPayload.response.message=~"admission webhook" を alert。 |
| 症状 | NAP(Node Auto-Provisioning)を有効化した翌週、請求書の GKE Compute が前月比 +400%。Cloud Logging で n2-highmem-96(96 vCPU / 768 GiB)が 6 台起動していた。 |
|---|---|
| 原因 | ある CronJob の Pod が resources.requests: {cpu: 80, memory: 600Gi} と誤って書かれていた(本来 80m / 600Mi)。NAP は「この Pod を schedule できる最小 node」として n2-highmem-96 を新規作成、Pod 終了後もscaleDown delay 10 分の間は課金。 |
| 処置 | ① 即時に gcloud container clusters update CLUSTER --autoprovisioning-max-cpu=32 --autoprovisioning-max-memory=128 でNAP 上限を設定 → ② resources.requests の誤りを修正 → ③ OPA Gatekeeper / Policy Controller で「requests.cpu > 16 または requests.memory > 64Gi の Pod は拒否」する Constraint を追加 → ④ LimitRange を全 namespace にデフォルト適用。 |
| 教訓 | NAP は強力だが「Pod request が malformed なら巨大 node が走る」。autoprovisioning-max-* の上限設定と、Admission Controller での request 制約が必須。NAP は profile + 上限を必ずペアで設定。 |
| 検知 | Monitoring の kubernetes.io/container/cpu/request_cores で request_cores > 16 の Pod 件数を alert。Billing の GKE Compute 日次変動 +30% で warn。 |
| 症状 | Pod が 5 分おきに OOMKilled / Evicted を繰り返し、HTTP 5xx 率 8%、SLO(99.9%)一発で違反。CPU 使用率は 30% 程度で余裕あり。 |
|---|---|
| 原因 | HPA を CPU メトリクスで設定(targetCPUUtilization: 70)+ 同じ Deployment に VPA をAuto モードで適用。VPA が requests を変更するたびに Pod が evict され、HPA は CPU 比率が変動するので scale 判断が安定しない。 |
| 処置 | ① VPA を Off / Initial / Recreate モードへ変更(Auto モードは HPA と併用不可と公式に明記)→ ② HPA は CPU でなくカスタム metric(requests/s, queue depth)で動かす → ③ VPA はRecommendation modeで値だけ取得し、人間が PR でレビューして反映。 |
| 教訓 | HPA(CPU/Memory)+ VPA Auto は同じ Deployment で禁忌。Multi-dimensional Pod Autoscaler(MPA)か、HPA をカスタム metric で、VPA は Recommendation のみに分離する。 |
| 検知 | kubernetes.io/container/restart_count の delta > 3 を 10 分窓で alert。kube_pod_status_reason{reason="Evicted"} も併用。 |
| 症状 | 夜間バッチ完了後の scale-in 時、HTTP API Pod が予告なく drain され、進行中リクエストが 502 に。月数千件の SLO 違反。 |
|---|---|
| 原因 | CA の --scale-down-unneeded-time がデフォルト 10 分のまま、かつ Pod 側の terminationGracePeriodSeconds: 30 + preStop hook なし。CA は node 上の Pod に SIGTERM を送り 30 秒後に SIGKILL。in-flight リクエストは中断。 |
| 処置 | ① Pod 側に preStop sleep 15s(LB が unhealthy 判定する時間を稼ぐ)+ terminationGracePeriodSeconds: 60 を設定 → ② PodDisruptionBudget(minAvailable: 80%)で同時 drain 数を制限 → ③ node lifecycle annotation cluster-autoscaler.kubernetes.io/safe-to-evict: "true" を batch Pod のみに付与し、API Pod は false に。 |
| 教訓 | CA の scaleDown は「node を消す = その node 上の全 Pod を evict」。preStop / GracePeriod / PDB の 3 点セットが必須。「Pod を安全に止める設計」と「node を畳む設計」は別物。 |
| 検知 | HTTP LB の backend latency p99 と kube_node_status_condition{condition="Ready",status="false"} の相関で検知。 |
| 症状 | Control Plane upgrade に伴う surge upgrade で、ある node pool の 5 node が並列で drain。3 replica の Deployment が全 Pod 同時 evictされ、サービス 4 分完全停止。 |
|---|---|
| 原因 | PDB が一切設定されておらず、node drain は全 Pod を即時 evict。3 replica が同一 zone の同一 node pool に偏って配置されていた(pod topology spread なし)。 |
| 処置 | ① PodDisruptionBudget を全 critical Deployment に作成(minAvailable: 50% または maxUnavailable: 1) → ② topologySpreadConstraints で zone / node pool 分散を強制 → ③ surge upgrade パラメータ --max-surge-upgrade=1 --max-unavailable-upgrade=0 に変更し同時 drain を 1 node に制限。 |
| 教訓 | PDB なし = node maintenance / upgrade 時にサービス無防備。Production の全 Deployment に PDB を Org Policy / Policy Controller で必須化する。「PDB 無しは production deployment ではない」と覚える。 |
| 検知 | Policy Controller / OPA で「kind: Deployment に対応する PDB が無ければ alert」。kubectl get pdb -A を定期 audit。 |
| 症状 | 夜間 ETL Pod が 403 Permission denied。gcloud auth list は KSA を表示するが、実際の token request がGCE metadata server の default SA tokenを返している。 |
|---|---|
| 原因 | Workload Identity はcluster level + node pool level の両方で有効化が必要。新規追加した node pool に --workload-metadata=GKE_METADATA を指定し忘れ、その node 上の Pod だけが旧 metadata server を使い node SA で動作。 |
| 処置 | ① gcloud container node-pools update POOL --workload-metadata=GKE_METADATA → ② KSA と GSA の binding 確認:gcloud iam service-accounts get-iam-policy GSA に serviceAccount:PROJECT.svc.id.goog[NS/KSA] が含まれるか → ③ Org Policy で iam.disableServiceAccountKeyCreation + compute.requireOsLogin を有効化し、node SA で動作する経路を塞ぐ。 |
| 教訓 | Workload Identity はcluster ⇔ node pool ⇔ KSA ⇔ GSA の 4 段リンク。1 つでも欠けるとsilent に node SA fallbackする(最も気付きにくい)。node pool 作成時の terraform module に必須化。 |
| 検知 | Cloud Audit Logs で protoPayload.authenticationInfo.principalEmail が node SA(...-compute@developer.gserviceaccount.com)の API call を alert。 |
| 症状 | 火曜 02:00 JST、自動 upgrade window 中に kubectl get pods が timeout。Argo CD の自動 sync が全 fail、デプロイパイプライン死亡。10 分後に復旧。 |
|---|---|
| 原因 | 本番 cluster がZonal cluster。Zonal cluster はcontrol plane が 1 zone のみで冗長化されないため、upgrade 中は API server が完全停止。Regional cluster は 3 zone に control plane を分散しローリング upgrade で zero downtime。 |
| 処置 | ① 既存 Zonal を Regional に変換するには新 cluster を Regional で作って migrate(in-place 変換不可)→ ② migration は ASM / Multi-cluster Ingress で blue-green → ③ 暫定対応としてmaintenance window を業務影響最小の時間帯に限定 + maintenance exclusion で繁忙期は upgrade 禁止。 |
| 教訓 | Production は必ず Regional cluster。月コスト差は cluster 管理料 $73 → $219(3 倍)だが、kube-apiserver 可用性は段違い。「Zonal は dev / 学習用、Production は Regional」を Org Policy で強制可。 |
| 検知 | Monitoring の kubernetes.io/cluster/api_server/request_count が 1 分以上 0 で alert。Argo CD の sync failure rate を SLI 化。 |
| 症状 | Spot node pool 上の 30 Pod が同時 preempt。CA は補充を試みるが code=ZONE_RESOURCE_POOL_EXHAUSTED で30 分間 capacity が確保できず、SLO 違反。 |
|---|---|
| 原因 | ① Spot 単独の node pool を 1 zone のみで構成 → ② capacity 枯渇時の fallback 設計なし → ③ backup-on-demand 的な on-demand node pool が無く、CA は Spot のみで補充を試行し続けた。 |
| 処置 | ① multi-zone Spot node pool(3 zone 分散) → ② on-demand fallback node pool を taint 付きで用意し、preferred-during-scheduling で Spot を優先、Spot 枯渇時のみ on-demand へスケジュール → ③ CA に --expander=priority を設定し、Spot pool を高優先度に → ④ Compute Engine Reservation(オンデマンド予約)で重要 workload の予約 capacity を確保。 |
| 教訓 | Spot は常に「容量無保証」。Multi-zone + on-demand fallback + Reservation の 3 段防御が production の最低ライン。「Spot だけの node pool」は SLO サービスには使わない。 |
| 検知 | CA の event log で NoScaleUp + no.scale.up.spot.capacity を alert。kube_pod_status_phase{phase="Pending"} 滞留時間。 |
| 症状 | 新規 Ingress(GCLB)経由のリクエストが間欠的に 502。Pod は Ready、Service の Endpoints も正常。GFE の access log に backend_connection_closed_before_data_sent_to_client。 |
|---|---|
| 原因 | BackendConfig(GKE Ingress 専用 CRD)で health check path を指定せず、GCLB はデフォルトで / へ GET。アプリの / は 200 を返すが応答時間 4 秒で、GCLB のデフォルト timeoutSec: 5 を時折超え unhealthy 判定。 |
| 処置 | ① BackendConfig で healthCheck: { type: HTTP, requestPath: /healthz, timeoutSec: 1, checkIntervalSec: 5, healthyThreshold: 1, unhealthyThreshold: 3 } を明示 → ② アプリに /healthz(DB connection 等の外部依存は含めず in-memory のみ確認)を実装 → ③ readinessProbe と BackendConfig health check を一致させる(path / port / timeout)。 |
| 教訓 | GKE Ingress の health check はBackendConfig で明示しない限り / がデフォルト。readinessProbe と独立に動作するので、両方を同じ条件で設計。healthz は外部依存を含めないのが鉄則。 |
| 検知 | LB の loadbalancing.googleapis.com/https/backend_latencies p99 と backend_status_code="5xx" 比率。 |
| 症状 | 監査チームから「先週 木曜 14:00〜18:00 の admin activity log が欠落」と指摘。SOC2 audit で「ログの完全性」要件違反のリスク。 |
|---|---|
| 原因 | GKE cluster の workload log が DEBUG 出力 + 大量 stack trace で1 分あたり 10 GBを超過し、Cloud Logging API write quota(プロジェクト毎の WriteRequestsPerMinutePerProject 等)を消費。Logging Agent の queue 溢れでaudit log も巻き添えで drop。 |
| 処置 | ① Log Router の Exclusion filter で workload の DEBUG ログを除外(severity < INFO) → ② audit log は専用 sink で別 project の独立 bucketへ → ③ 重要 log は Required log buckets(_Required は exclusion 不可)またはBigQuery sink + Cloud Storage sink で二重冗長化 → ④ Quota 上限引き上げ申請。 |
| 教訓 | Cloud Logging は「無限に飲み込んでくれる」訳ではない。quota / agent buffer / sink 経路の 3 つに上限がある。audit log と workload log は経路分離が原則。 |
| 検知 | logging.googleapis.com/byte_count と logging.googleapis.com/dropped_log_entry_count を monitoring。Quota usage は serviceruntime.googleapis.com/quota/exceeded で alert。 |
9.2 GKE コスト構造の解剖(Standard vs Autopilot)
GKE の請求書は「cluster 管理料 + compute 料 + storage 料 + network 料」の 4 階層で構成されます。Standard と Autopilot でcompute 課金単位が決定的に異なるため、ワークロード特性により最適解が変わります。
9.2.1 主要コンポーネント別の課金(2026 年時点)
| コンポーネント | Standard | Autopilot | 備考 |
|---|---|---|---|
| Cluster 管理料 | $0.10 / hour(≒ 月 $73) | $0.10 / hour(≒ 月 $73) | 無料枠:billing account ごとに 1 zonal cluster 無料 |
| Compute(Pod / Node) | node の VM 料金(GCE 価格) | Pod の vCPU + Memory request(per-Pod 課金) | 後述の単価表参照 |
| Regional cluster 追加料 | 同じ $0.10/h(control plane 冗長分は無料) | 同じ $0.10/h | 2024 以降は zonal と同額に統一 |
| Persistent Disk | Standard PD $0.04/GB-month、SSD PD $0.17/GB-month | 同じ | scale 後に attach されたまま残ると累積 |
| Load Balancer | $18-25 / 月 / forwarding rule + データ処理料 | 同じ | Ingress 1 つあたり管理コスト固定 |
| Egress(cross-region / Internet) | $0.01〜0.12 / GB | 同じ | multi-region cluster で要注意 |
| Logging / Monitoring | $0.50 / GB ingested(_Default は 50 GB / 月無料) | 同じ | workload log が支配的になりやすい |
「Autopilot mode bills you for the CPU, memory, and ephemeral storage that your Pods request while they are running.」 — GKE pricing — Autopilot mode
9.2.2 Autopilot の Pod 単価(General-purpose, us-central1)
| リソース | 単価 | 備考 |
|---|---|---|
| vCPU | $0.0445 / vCPU-hour | Pod の resources.requests.cpu 合計で課金 |
| Memory | $0.0049 / GiB-hour | Pod の resources.requests.memory 合計で課金 |
| Ephemeral storage | $0.0000548 / GiB-hour | 1 GiB がデフォルト、明示指定可 |
| Spot Pod | 上記から最大 60-91% 割引 | Pod spec に spot: true 指定 |
| Balanced / Scale-Out / Accelerator | compute class により別単価 | GPU / Arm 等は加算あり |
9.2.3 Standard の Node 単価(参考、n2-standard-4 = 4 vCPU/16 GiB, us-central1)
| machine type | vCPU | memory | 単価 / hour(on-demand) | Spot 単価(≒ 60-91% off) |
|---|---|---|---|---|
| e2-medium | 1 | 4 GiB | $0.033 | $0.010 |
| e2-standard-4 | 4 | 16 GiB | $0.134 | $0.040 |
| n2-standard-4 | 4 | 16 GiB | $0.194 | $0.058 |
| n2-standard-16 | 16 | 64 GiB | $0.7763 | $0.233 |
| n2-highmem-8 | 8 | 64 GiB | $0.524 | $0.157 |
| c2-standard-16(compute-optimized) | 16 | 64 GiB | $0.836 | $0.251 |
9.2.4 Autopilot vs Standard 単価の損益分岐点
・Autopilot:10 vCPU × $0.0445 × 730h + 20 GiB × $0.0049 × 730h = $325 + $72 ≒ 月 $397 + $73(管理料)= $470
・Standard(n2-standard-16 × 1 = 16 vCPU/64 GiB に詰める):$0.7763 × 730h + $73 = $567 + $73 = $640(node 利用率 62.5%)
→ 5 Pod 程度なら Autopilot が約 27% 安い。
逆の条件:Pod 50 個、各 2 vCPU / 4 GiB(合計 100 vCPU / 200 GiB)
・Autopilot:100 vCPU × $0.0445 × 730h + 200 GiB × $0.0049 × 730h = $3,249 + $716 = $3,965 + $73 = $4,038
・Standard(n2-standard-16 × 7 で 112 vCPU 詰める):$0.7763 × 730h × 7 + $73 = $3,968 + $73 = $4,041(node 利用率 89%)
→ 50 Pod 規模で Standard と Autopilot は同等。bin packing 効率が 89% を超えるなら Standard 有利、それ未満なら Autopilot 有利。
Spot 混在の条件:上記 50 Pod のうち 30 Pod を Spot に → Standard の方が Spot 適用範囲が広く(node 全体)、約 35-50% 削減可能。
9.3 コスト肥大化の典型パターン 6 件
症状:node 利用率 30% で月 $5,000、Pod 数は 100 程度。Cloud Monitoring の node_cpu_allocatable_utilization も 30%。
原因:開発者が「念のため」と requests.cpu を実使用の 5 倍に設定。schedule 時に node を埋められず、CA が常に新 node を起動。
対処:① VPA Recommendation mode で過去 30 日の actual usage から推奨 request を取得 → ② requests = p95(actual) × 1.2 を目安に PR → ③ CA を --autoscaling-profile=optimize-utilization に変更しbin packing 優先。
症状:Pod 数 500(各 0.25 vCPU / 256 MiB の microservice)。Autopilot で月 $4,000、同じ Pod を Standard に置けば $1,500 程度。
原因:Autopilot はPod 数に比例して minimum overheadがある(各 Pod に kube-system overhead を加算)。さらに 最小 request(0.25 vCPU、0.5 GiB)に丸められるため、それ以下の小さな Pod でも 0.25 vCPU 分課金される。
対処:① 軽量 Pod 大量ならStandard + bin packingに移行 → ② どうしても Autopilot を使うなら同 namespace 内で複数 Pod を 1 つに統合(sidecar 削減等) → ③ Autopilot 公式の最小リソース仕様を採用前に確認。
症状:API サーバ用 node pool に n2-highmem-16(16 vCPU / 128 GiB)を採用。CPU 使用率 70%、メモリ使用率 15%。
対処:workload の CPU:Memory 比率を測定し、最適 machine family を選定。
・CPU bound(比率 1:2 未満)→ n2-highcpu 系(vCPU:RAM = 1:1)
・汎用(比率 1:4 程度)→ n2-standard 系(1:4)
・Memory bound(比率 1:8 以上)→ n2-highmem 系(1:8)
・特殊比率 → Custom machine type(N1/N2 のみ可)で 1:3 等を指定。
症状:node pool A は GPU 専用、B は memory-heavy、C は default。各 pool の利用率がそれぞれ 20-40%。
対処:① node pool 統合(GPU 以外は default に統合)→ ② nodeAffinity を preferredDuringScheduling に緩和し、必要なら他 pool にも落ちる設計 → ③ Compute Class(Autopilot)で workload class を分離。
症状:StorageClass で 100 GiB SSD PD を Default 設定。dev 環境の Pod が PVC 100 個 = 10 TB、実使用 500 GB。月 $1,700 → $85 の浪費。
対処:① StorageClass に allowVolumeExpansion: true + 初期 10 GiB → ② Filestore は最小 1 TiB からなので、共有不要なら GCSFuse / PD で代替 → ③ PV reclaim policy を Delete に(Retain だと Pod 削除後も残る) → ④ Snapshot 数とサイズを定期 audit。
症状:env × team × region で cluster が 50 個、各 $73 × 50 = 月 $3,650 が cluster 管理料だけで消失。各 cluster の node 利用率も 20% 以下。
対処:① multi-tenant cluster(namespace 分離 + ResourceQuota + NetworkPolicy) → ② team 分離は fleet(Anthos / GKE Enterprise)で論理境界 → ③ env 分離は最低限(dev / stg / prd の 3 cluster × region)に圧縮 → ④ shared services cluster(CI/CD agent、Prometheus 等)を 1 つに集約。
9.4 最適化テクニック 10 個
- Autopilot vs Standard の判断軸:
・Autopilot 有利:小規模(< 30 Pod)、運用工数最小化、SRE 不在、初学者
・Standard 有利:大量 Pod(> 50)、特殊 DaemonSet、bin packing 80%+、GPU、特殊 networking - Cluster Autoscaler の
optimize-utilizationprofile:--autoscaling-profile=optimize-utilizationでscaleDown を積極化、node 利用率 80%+ を目指す。デフォルトbalancedは availability 優先。 - Bin packing 最適化(適切な resources.requests):VPA Recommendation mode で過去 30 日の実測 →
requests = p95 × 1.2を PR 化。requests 適正化が単一最大のコスト削減手段。 - Spot node pool の活用:stateless / バッチ / dev は Spot で 60-91% 削減。production はmulti-zone Spot + on-demand fallback + PDB + preStop の 4 点セット。
- Node Auto-Provisioning(NAP)+ 上限設定:NAP は新規 machine type を自動選定し bin packing 効率化。必ず
--autoprovisioning-max-cpu/--max-memoryで上限を設定。 - Vertical Pod Autoscaler in Recommendation mode:Auto モードは HPA 競合・restart 多発のため本番禁止。Recommendation mode で値だけ取得し人間レビュー。
- GKE Cost Allocation + Cost Insight:cluster 単位で
billing-exportを namespace / label 別に按分可能。BigQuery + Looker Studio で部門別 dashboard。 - Multi-tenant cluster(namespace 分離):cluster 数を圧縮し管理料・base capacity を節約。
ResourceQuota+LimitRange+NetworkPolicy+Hierarchical Namespaces (HNS)でテナント分離。 - Pod Disruption Budget の適切な設定:production は必ず PDB。
minAvailable: 50%推奨。Org Policy / Policy Controller で必須化。 - Regional vs Zonal の trade-off:
・Regional:control plane 冗長、upgrade zero downtime、node も multi-zone で配置可、cluster 管理料は zonal と同額(2024 以降)
・Zonal:単一 zone のみ、upgrade 中 API 停止、dev / 学習用
→ production は Regional 一択
9.5 監視・アラート設計(GKE 特有)
9.5.1 監視すべき主要 metric
| metric | 説明 | SLI / alert 例 |
|---|---|---|
kubernetes.io/container/cpu/request_utilization | request 比率の actual usage | 1 週間平均 < 30% で over-provision 候補 |
kubernetes.io/container/memory/request_utilization | memory request 比率 | 同上 |
kubernetes.io/container/restart_count | container 再起動回数 | delta > 3 / 10min で alert |
kubernetes.io/node/cpu/allocatable_utilization | node 全体の利用率 | node pool 平均 < 50% で集約検討 |
kubernetes.io/autoscaler/cluster_autoscaler/unschedulable_pods_count | schedule 不能 Pod 数 | 5 分以上滞留で alert |
kubernetes.io/cluster/api_server/request_count | kube-apiserver 受信数 | 1 分間 0 なら apiserver down |
logging.googleapis.com/dropped_log_entry_count | log drop 数 | 1 件でも warn |
| Pod eviction event | Cloud Logging で jsonPayload.reason="Evicted" | 1 件で warn、memory pressure 検知 |
9.5.2 GKE 特有の SLO 設計
9.5.3 コスト・容量アラート
CPUS, IN_USE_ADDRESSES, SSD_TOTAL_GB)を 80% で warn。Spot capacity に依存するならpreemptible quota も別途9.6 試験ポイント(Section 9 要点)
- Autopilot の制約:hostPath / hostNetwork / 特権コンテナ禁止。セキュリティ / 監視 DaemonSet は動かない可能性
- Production cluster は Regional。Zonal は upgrade 中 control plane 停止
- Workload Identity は cluster + node pool + KSA + GSA の 4 段。1 つでも欠けると node SA に silent fallback
- PDB なし = production 失格。node drain / upgrade 時のサービス停止リスク
- HPA + VPA Auto は禁忌。VPA は Recommendation mode で人間レビュー
- NAP は上限設定必須。malformed request で巨大 node が走るリスク
- cluster 管理料は $0.10/h(≒ $73/月)、billing account ごとに zonal 1 つ無料
- Autopilot 単価:$0.0445/vCPU-h + $0.0049/GiB-h(Pod request ベース)
- 「軽量 Pod 大量」は Standard 有利、「数 Pod だけ」は Autopilot 有利。bin packing 効率 89% がおおむね損益分岐
- Spot は multi-zone + on-demand fallback + PDB + preStop の 4 点セットで初めて production grade
- Cluster Autoscaler profile:
balanced(デフォルト・可用性優先) vsoptimize-utilization(コスト優先)
10. Cloud Run 運用深掘り:事故・コスト・肥大化対策
Cloud Run は「リクエストベースの完全サーバレス compute」として運用工数最小ですが、concurrency / cpu-allocation / min-instances の 3 つの設定を理解しないと、請求書が想定の数十倍になることがあります。本章では Section 2.7 / 7.5 の Cloud Run 事故を発展させ、Worker Pool・Cloud Run Jobs・gen1↔gen2・VPC Connector・Secret 連携などの深部を扱います。
「By default, a container instance is allocated CPU only during request processing. You can configure your service to always allocate CPU to container instances.」 — Cloud Run CPU allocation
10.1 重大事故ケース 10 件(実務深掘り版)
各ケースは 症状 / 原因 / 処置 / 教訓 / 検知 metric の 5 行で構成。Section 7.5 の事故と重複しないように、Worker Pool・Jobs・Secret・gen 切替・size limit・VPC Connector・Cloud Run Functions 等の深部を扱います。
| 症状 | API 全体の SLO(p99 < 1 秒)に対し、p99 = 3.2 秒。0.5% のリクエストが cold start に当たり、Java Spring Boot の起動 + JIT で 3 秒。エンドユーザーから「時々遅い」苦情。 |
|---|---|
| 原因 | min-instances=0 でアイドル中はスケールゼロ。新規リクエスト時に container start + アプリ起動が必要。Java / .NET 系は cold start 2-5 秒が一般的。 |
| 処置 | ① min-instances=1 設定 + CPU boost 有効化(gen2 で startup 時 CPU 倍増) → ② アプリ側でAOT compilation(Spring Boot → GraalVM Native Image)で起動 100ms へ短縮 → ③ それでも厳しければCloud Run 不向き、GKE で常時 Pod 化を検討。 |
| 教訓 | cold start は言語ランタイム選定に大きく依存。Java / .NET = 数秒、Go / Rust / Node = 数百ms、Python = 数百ms-1秒。SLO 厳しいならmin-instances ≥ 1 + CPU boost を基本とし、コストとのトレードオフを設計時に決める。 |
| 検知 | run.googleapis.com/container/startup_latencies p95、および run.googleapis.com/container/instance_count の min を監視。 |
| 症状 | Pub/Sub push 経由の I/O bound worker(DB 待ち中心)を Cloud Run で実装。concurrency: 1 のまま運用、月 $8,000。同じワークロードを GKE Deployment 化で月 $100 程度の見積もり。 |
|---|---|
| 原因 | 「Pub/Sub push は 1 message = 1 リクエストだから concurrency=1 で良い」という誤解。I/O 待ち時間中に同 instance で他の message も処理できる。 |
| 処置 | ① concurrency=80(max)に変更し負荷試験 → ② Pub/Sub の maxOutstandingMessages / maxConcurrentDispatch を調整 → ③ 長時間ジョブは Cloud Run Jobs に分離(Cloud Run service の max request timeout は 60 分) → ④ Worker Pool(Cloud Run の新機能、リクエストなしの常時実行)を検討。 |
| 教訓 | concurrency=1 は「state shared / thread unsafe / heavy computation」のみ。I/O bound なら 80(max)。負荷試験でレイテンシが許容範囲内に収まる最大 concurrency を見つけ設定。 |
| 検知 | run.googleapis.com/container/instance_count の積分 × 単価 を予測し、month-over-month で警戒。 |
| 症状 | 月数千リクエストの社内ツール(ほぼアイドル)に月 $200。gcloud run services describe で cpuAllocation: ALWAYS が判明。 |
|---|---|
| 原因 | WebSocket 機能を「将来追加する予定」で CPU always allocated を ON にし、結局 WebSocket は未実装のまま。request 処理外でも CPU + Memory が常時課金される(min-instances=1 の場合)。 |
| 処置 | ① CPU allocation を --no-cpu-throttling から外す(デフォルト:request 中のみ CPU 割当) → ② WebSocket / streaming / バックグラウンド処理が実際に必要かを設計時に判定 → ③ 不要ならrequest-based billing(デフォルト)で大幅削減。 |
| 教訓 | CPU always allocated はWebSocket / SSE / 長時間 streaming / 背景処理の 4 ユースケース限定。それ以外は request-based。公式 CPU allocation guide ↗ を必ず一読。 |
| 検知 | Cloud Asset Inventory で resource.type="run.googleapis.com/Service" + spec.template.spec.containers[].resources.cpuIdle=false の service を日次 audit。 |
| 症状 | 新 revision を deploy するたび ContainerHealthCheckFailed: container failed to start。前 revision に rollback で動く。 |
|---|---|
| 原因 | Secret Manager 連携で --update-secrets=API_KEY=my-secret:latest と指定していた。Secret が rotation され latest が新 version になったが、新 version が disabled 状態。Cloud Run は revision 起動時に Secret を pull し、disabled だと取得失敗。 |
| 処置 | ① Secret は version pin(my-secret:7)を原則化 → ② rotation 時は新 version を enabled で作成 → Cloud Run revision 再 deploy → 旧 version disable の順序 → ③ Cloud Run のSecret access service account(roles/secretmanager.secretAccessor)が runtime SA に付与されているか確認。 |
| 教訓 | Cloud Run の Secret は「mount 時に取得」型(一部)と「環境変数として展開」型がある。latest は production で使わず、必ず version pin。rotation は両 version を一時的に enabled に。 |
| 検知 | Cloud Logging で resource.type="cloud_run_revision" + severity=ERROR + jsonPayload.message=~"secret" を alert。 |
| 症状 | 画像アップロード API(10-50 MB の画像)が 413 Request Entity Too Large。application/json body 32 MB を超えるリクエストも同様。 |
|---|---|
| 原因 | Cloud Run gen1 のHTTPS request payload size limit は 32 MB(hard limit)。streaming も非対応。 |
| 処置 | ① gen2 (Cloud Run Execution environment second generation) に切替:gen2 はrequest streaming + 大容量 body 対応(理論上 size 制限緩和)→ ② アプリ設計を変えdirect upload to GCS(signed URL 経由)+ Cloud Run は metadata のみ受信 → ③ どうしても受信するならchunked upload(multipart)。 |
| 教訓 | gen1 / gen2 の制約は意外と異なる。Execution environments 公式 ↗ を読み、機能要件と照合してから採用。大容量 upload は GCS signed URL で OS-bypass が定番。 |
| 検知 | HTTP LB の backend_status_code="413" 比率を monitoring。 |
| 症状 | 週次 ETL(30 時間ジョブ)を Cloud Run Jobs で実装。--task-timeout=86400(24h)以上を指定すると INVALID_ARGUMENT。 |
|---|---|
| 原因 | Cloud Run Jobs のtask timeout 上限は 24 時間(hard limit)。Cloud Run service の request timeout も 60 分が上限。 |
| 処置 | ① ETL を複数 task に分割(--tasks=N --parallelism=K)し各 task < 24h に → ② 長時間ジョブはGKE CronJob または Compute Engine + Cloud Scheduler へ → ③ Spark / BigQuery 系の workload ならDataflow / BigQuery scheduled query へ。 |
| 教訓 | Cloud Run は「短時間 stateless workload」用。長時間バッチは分割 or 他サービス。サービス選定時にSLA / timeout / size 制約を一覧で確認。 |
| 検知 | Cloud Run Jobs の execution_count{status="cancelled_timeout"}。 |
| 症状 | Cloud Run service 20 個、それぞれ専用 Serverless VPC Connector を作成。e2-micro × 2 instance × 20 connector × 24h × 30d = 月 $144 が idle で消える + データ処理料も別途。 |
|---|---|
| 原因 | 「サービスごとに分離した方がきれい」と思い1 service = 1 connectorで運用。Connector はmin_instances=2 で常時課金(e2-micro 単位)。さらに connector 経由 egress は追加データ処理料。 |
| 処置 | ① Direct VPC egress(gen2 専用)に移行:Connector 不要、direct に VPC へ → ② Connector を共用する場合はregion 単位で 1 つ、複数 service で share → ③ VPC 内通信不要ならconnector を外す(Cloud Run はデフォルト public internet 経由)。 |
| 教訓 | Serverless VPC Connector はidle でも常時課金(min instance 2 が必須)。gen2 + Direct VPC egress が新規 production の第一選択。Direct VPC egress 公式 ↗ |
| 検知 | Cloud Asset Inventory で project 内の Connector 数を月次 audit。同 region 内 Connector の重複を検知。 |
| 症状 | gen1 で動いていた service を --execution-environment=gen2 に変更したら全 revision が起動失敗。ContainerHealthCheckFailed。 |
|---|---|
| 原因 | gen1 と gen2 でfilesystem / network namespace 等の挙動差異がある。アプリは /tmp を tmpfs 前提で使っており、gen2 では実 disk based に変わったため I/O latency が増え startup probe が間に合わなかった(gen1 vs gen2 の挙動差は時期により変動する)。さらに gen1 で sandbox API(一部 syscall)を使っていた箇所が gen2 では別挙動。 |
| 処置 | ① 新 revision に traffic 0% で deploy(traffic splitting)→ ② 動作確認後に段階的に traffic 移動 → ③ アプリのfilesystem 前提 / syscall 依存箇所を gen2 互換に修正 → ④ startupProbe.initialDelaySeconds / periodSeconds / failureThreshold を調整。 |
| 教訓 | gen 切替は「同じ container でも挙動が違う」と覚悟する。traffic 0% deploy → 段階移行を rule に。Execution environments 比較 ↗ |
| 検知 | Cloud Logging で revision deploy 時の ContainerHealthCheckFailed を即時 alert。 |
| 症状 | Pub/Sub trigger の Cloud Run Functions(Python 3.11、Flask wrapping)。p99 invocation latency が 2.5 秒、許容 500ms を大幅超過。 |
|---|---|
| 原因 | Cloud Run Functions はCloud Run の上に Functions Framework が乗った構造。Python の場合、import の重い library(pandas、tensorflow 等)が cold start に直撃。さらに Pub/Sub trigger はmin-instances を上げづらい(リクエスト ≒ message のため、ピーク予測しづらい)。 |
| 処置 | ① min-instances=1 + CPU boost → ② 重い import を遅延読み込み(関数内で import)→ ③ Cloud Run Functions ではなくCloud Run service として書き換え(より細かい設定が可能)→ ④ どうしても cold start を許容できないなら GKE Deployment へ。 |
| 教訓 | Cloud Run Functions = Cloud Run service の「より簡単版」であり、内部は同じ。SLO 厳しいならCloud Run service として明示的に管理した方が制御性が高い。Functions Framework のオーバーヘッドも考慮。 |
| 検知 | cloudfunctions.googleapis.com/function/execution_times p99 と cloud_function_execution_count{status="ok"}。 |
| 症状 | 夜間 ETL Job が transient error で 1 task fail → --max-retries=3 設定で 3 回再実行 → DB に同じレコードが 4 行登録。アプリは冪等性なし。 |
|---|---|
| 原因 | Cloud Run Jobs はtask 単位での自動 retryを提供(--max-retries)。同じ CLOUD_RUN_TASK_INDEX で再実行されるが、アプリ側で冪等性を保証しないと重複書き込みになる。 |
| 処置 | ① アプリ側で冪等性を担保(INSERT ... ON CONFLICT DO NOTHING、UUID 主キー等)→ ② retry が必要ならidempotency key を CLOUD_RUN_TASK_INDEX + CLOUD_RUN_TASK_ATTEMPT で生成 → ③ 並列実行を考慮:--parallelism=N で N task 同時実行、それぞれが完了するまで Job は終わらない。 |
| 教訓 | 「retry」と「冪等性」は必ずセット。retry を有効にする時点で、アプリ側で「同じ task が複数回走っても安全」を担保する必要がある。分散システムの大原則。 |
| 検知 | DB 側で unique constraint violation count を monitoring。task の CLOUD_RUN_TASK_ATTEMPT > 0 件数を週次 review。 |
10.2 Cloud Run コスト構造の解剖
Cloud Run の請求は「vCPU 秒 + Memory 秒 + Request 数 + Network egress」の 4 軸で構成され、さらに「CPU allocation モード」と「min-instances」で課金挙動が大きく変わります。理解の鍵は「いつ vCPU/Memory が課金されるか」です。
10.2.1 主要コンポーネント別の課金(2026 年時点、Tier 1 region)
| コンポーネント | 単価 | 備考 |
|---|---|---|
| vCPU 秒(request-based, throttled) | $0.000024 / vCPU-sec | request 処理中のみ課金(デフォルト) |
| Memory 秒(request-based) | $0.0000025 / GiB-sec | 同上 |
| vCPU 秒(always allocated) | $0.000018 / vCPU-sec | 常時課金だが単価は安い(throttled の 75%) |
| Memory 秒(always allocated) | $0.000002 / GiB-sec | 同上 |
| Request 数 | $0.40 / 100 万 requests | 無料枠:月 200 万 requests |
| Network egress | GCE 通常 egress 料金 | 同 region 内 0、Internet $0.12/GB 等 |
| min-instances(idle 状態) | always allocated 単価で常時課金 | min=1 で常時 1 instance 分の vCPU + Memory |
| Cloud Run Jobs(vCPU/Memory) | always allocated と同単価 | task の execution 時間で課金 |
「With CPU always allocated, your container instances always have CPU allocated. This is useful for background tasks or for services that have an active connection to a client.」 — Cloud Run CPU allocation
10.2.2 CPU allocation モードの違い(最重要)
| 項目 | CPU only during request processing(throttled, default) | CPU always allocated |
|---|---|---|
| 課金タイミング | request 処理中のみ vCPU + Memory 課金 | instance 起動中ずっと vCPU + Memory 課金 |
| vCPU 単価 | $0.000024 / vCPU-sec | $0.000018 / vCPU-sec(25% 安い) |
| Memory 単価 | $0.0000025 / GiB-sec | $0.000002 / GiB-sec(20% 安い) |
| Request 課金 | $0.40 / 100 万 requests | 無料 |
| 背景処理 | request 終了後 CPU が throttle、async/background 動作不可 | 常時 CPU 利用可、background 処理 OK |
| WebSocket / SSE | 非推奨(connection 維持中も CPU throttle) | 必須 |
| 適用ケース | stateless API、ほぼ request-response 完結 | WebSocket、SSE、background task、長時間処理 |
10.2.3 Free tier の正確な仕様
10.2.4 試算例:3 つの典型ワークロード
① 標準 stateless API(CPU throttled, min-instances=0, concurrency=80):
・実 vCPU-秒 = (1000 万 × 0.2s) / 80 = 25,000 vCPU-sec → $0.60
・実 Memory-秒 = (1000 万 × 0.2s × 0.5) / 80 = 12,500 GiB-sec → $0.03
・Request = 1000 万 / 100 万 × $0.40 = $4.00
→ 合計約 $4.63 / 月(free tier 適用後はほぼ無料)
② cold start NG API(min-instances=1, CPU throttled):
・min-instances=1 の idle はalways allocated 単価で課金
・idle 時間 ≒ 月 730h(リクエスト処理時間は微小)= 730 × 3600 = 2,628,000 sec
・vCPU 課金 = 2,628,000 × $0.000018 = $47.30
・Memory 課金 = 2,628,000 × 0.5 GiB × $0.000002 = $2.63
・Request 課金 = $4.00
→ 合計約 $54 / 月(min-instances 効果で +$50)
③ WebSocket / 背景処理(min-instances=2, CPU always allocated, concurrency=80):
・常時 2 instance × 730h × 3600s = 5,256,000 sec
・vCPU 課金 = 5,256,000 × $0.000018 = $94.60
・Memory 課金 = 5,256,000 × 0.5 GiB × $0.000002 = $5.26
・Request 課金 = 0(always allocated は無料)
→ 合計約 $100 / 月
10.3 コスト肥大化の典型パターン 6 件
症状:開発者全員が「cold start = 悪」と思い、全 service で min-instances=2 設定。月数千リクエストの社内ツール 30 個 × $50/月 = 月 $1,500 が idle で消失。
対処:① SLO 不要ならmin-instances=0(cold start 体感は気にしない) → ② 業務時間のみ事前 warm-up が必要なら Cloud Scheduler + curl で平日朝のみ warm 化 → ③ 真に必要なサービスにのみ min-instances を限定。「default は min=0、例外的に min>0」の運用方針を明文化。
症状:チームの 50 service のうち 12 service が CPU always allocated 設定。WebSocket は実装されていないにも関わらず常時課金。
対処:① Cloud Asset Inventory で cpuIdle 設定を audit → ② WebSocket / SSE / 背景処理が無いサービスは throttled に変更 → ③ Org Policy / Terraform module で「明示的なフラグなしには always allocated を ON にできない」ルール。
症状:DB 待ちが 90% を占める API で concurrency=1。各 request 200ms のうち 180ms が DB 待ち。本来 concurrency=80 で同 instance が 80 リクエスト並列処理できるはず。
対処:① 必ず負荷試験を行い concurrency × throughput のスイートスポットを発見 → ② 一般則:I/O bound は 80(max)、CPU bound は 8-16、メモリ heavy なら 1-4 → ③ --cpu-throttling と --concurrency はセットで設計。
症状:「VPC 内のサービスにアクセスする予定」で 20 service すべてに Serverless VPC Connector を割当。実際に VPC 内アクセスするのは 3 service のみ。残り 17 service は connector idle で月 $5 × 17 = $85 浪費。
対処:① VPC 内通信が本当に必要かを再評価(多くの GCP サービスは Public エンドポイント + IAM で十分) → ② 必要ならDirect VPC egress(gen2)に移行(Connector 不要) → ③ Connector を残す場合はregion 単位で 1 つを共用。
症状:100 task の Job で 10 task が flaky で retry 3 回。task 数 100 → 130 task 実行、課金 30% 増。さらに冪等性なしで DB に重複行。
対処:① flaky の根本原因を fix(network retry、timeout 拡張等) → ② 冪等性を必ず実装 → ③ retry は3 回までに制限、それ以上は dead letter queue(GCS / Pub/Sub)へ転送 → ④ Job 全体の cost を CLOUD_RUN_TASK_ATTEMPT ごとに分析。
症状:min-instances=1 で常時課金しているのに cold start も 2 秒あり、コスト・性能とも悪化。
対処:① gen2 + CPU boost(--cpu-boost)を有効化、startup 時のみ CPU 倍増 → ② startup probe を適切に設定(cold start を待ってから healthcheck) → ③ 軽量ランタイム(Go / Rust / Node + minimal image)に変更し cold start を 100-300ms に圧縮 → ④ min-instances=0 + CPU boost で「ほぼ cold start 体感ゼロ」を狙う。
10.4 最適化テクニック 10 個
- concurrency 設定の負荷試験:1 / 8 / 32 / 80 で実機計測。レイテンシ劣化が許容範囲内の最大値を採用。I/O bound = 80、CPU bound = 8-16。
- CPU always allocated は必要時のみ:WebSocket / SSE / 背景処理 / 長時間 streaming の4 ユースケース限定。それ以外は throttled(デフォルト)。
- min-instances は SLO 要件 vs cold start トレードオフで決定:SLO 厳しい (p99 < 1s) なら 1-2、それ以外は 0。「全 service で min=2」は禁忌。
- CPU boost で cold start 短縮(gen2):
--cpu-boostで起動時 CPU 倍増、cold start 50% 短縮。コスト影響は startup 数秒のみ。 - Direct VPC egress(gen2)で Connector コスト削減:Serverless VPC Connector の min instance 2 + データ処理料を回避。公式 ↗
- Cloud Run Functions vs service の使い分け:
・Functions:Pub/Sub trigger、Storage trigger、HTTP の短時間関数、簡易デプロイ
・service:細かい設定が必要、複雑なルーティング、長時間処理、自前 Dockerfile - Always-on CPU vs request-based の判断軸:
・request-based:stateless API、サンプル数 90% 以上のユースケース
・always-on:WebSocket / SSE / background processing(明確な要件があるときのみ) - revision tag で blue-green deploy:
gcloud run deploy --tag=blue --no-trafficで新 revision を tag 経由でテスト可、本番 traffic は 0% のまま検証。 - traffic splitting で canary release:
--to-revisions=blue=10,green=90で段階的に traffic 移行。エラー率を見ながら 10 → 50 → 100%。 - Cloud Run Jobs のリソース最適化:
・--cpu/--memoryを実測ベースで設定(過剰スペック禁止)
・--parallelismで並列度調整(高すぎると DB 負荷、低すぎると総時間長期化)
・冪等性 +--max-retries=3で flaky 対策
・--task-timeoutを p99 × 1.5 で設定
10.5 監視・アラート設計(Cloud Run 特有)
10.5.1 監視すべき主要 metric
| metric | 説明 | SLI / alert 例 |
|---|---|---|
run.googleapis.com/request_count | request 数(status code 別) | 5xx 率 > 1% で alert |
run.googleapis.com/request_latencies | request latency 分布 | p99 > SLO で alert |
run.googleapis.com/container/startup_latencies | cold start 時間 | p95 > 2s で warn |
run.googleapis.com/container/instance_count | instance 数 | min との乖離、max への張り付き |
run.googleapis.com/container/cpu/utilizations | CPU 使用率 | 常時 < 30% で over-provision 候補 |
run.googleapis.com/container/memory/utilizations | Memory 使用率 | > 90% で OOM リスク |
run.googleapis.com/container/billable_instance_time | 課金対象 instance 時間 | コスト試算の基礎 |
run.googleapis.com/container/max_request_concurrencies | 同時 request 上限到達回数 | frequent なら concurrency 引き上げ検討 |
10.5.2 Cloud Run 特有の SLO 設計
10.5.3 コスト・容量アラート
minScale を週次 audit、minScale > 0 の service リストを Slack 通知cpuIdle = false の service を日次レポート(WebSocket 等の正当理由がない service を検出)instance_count == max-instances が 5 分以上続いたら scale-out 上限引き上げ検討10.6 試験ポイント(Section 10 要点)
- CPU allocation の 2 モード:
throttled(request-based, デフォルト) vsalways allocated(常時課金、WebSocket / 背景処理用) - concurrency は I/O bound = 80(max)、CPU bound = 8-16。1 のままだと最大 80 倍のコスト
- min-instances=0 がデフォルト・推奨。SLO 厳しいときのみ 1-2、全 service で >0 は禁忌
- CPU boost は gen2 のみ、cold start 50% 短縮、コスト影響は startup 数秒のみ
- Free tier:月 180,000 vCPU-秒 + 360,000 GiB-秒 + 200 万 requests(request-based のみ対象)
- VPC アクセスは gen2 + Direct VPC egress 推奨、Serverless VPC Connector は idle でも min 2 instance 課金
- Secret は version pin(latest 禁止)、rotation 時は両 version enable
- Cloud Run service の request timeout は最大 60 分、Cloud Run Jobs の task timeout は最大 24 時間
- gen1 vs gen2 の挙動差異(filesystem、syscall、size limit、streaming)を採用前に確認
- retry と冪等性は必ずセット、Cloud Run Jobs の
--max-retriesは冪等性前提で有効化 - blue-green / canary は revision tag + traffic splitting で簡単実現
- HPA に相当する scale は自動、request rate ベース。手動制御は
--max-instancesのみ