PCD 合格対策

セクション3:デプロイ用クラウドネイティブアプリの構成

公式試験ガイド 042426版 — Section 3: Configuring cloud-native applications for deployment

24%
出題比重
2
サブトピック
~12問
想定問数
Cloud Run/GKE
二本柱
🎯 このセクションの核心 Cloud Run と GKE の使い分け + それぞれのベストプラクティスが出題の核。 Cloud Run のリビジョン管理 / Cloud Run Jobs / Eventarc / Apigee 統合、 GKE の Autopilot / Standard / Deployment / Service / Ingress / HPA / Probe / Workload Identity がそれぞれ深掘り対象。

3.1 Cloud Run へのデプロイ

Cloud Run の 3形態

Cloud Run Services

  • HTTP/gRPC リクエスト駆動
  • 常時稼働(min-instances 設定可)
  • リビジョン管理、トラフィック分割
  • HTTPS 自動付与(*.a.run.app
  • タイムアウト最大 60分
Web API、マイクロサービス、Webhook 受信

Cloud Run Jobs

  • HTTP リクエスト不要
  • バッチ実行(タスク数、並列数を指定)
  • タイムアウト最大 24時間
  • Cloud Scheduler / Workflows / Eventarc で起動
ETL、定時バッチ、データ処理、マイグレーション

Cloud Run Functions

  • 関数単位デプロイ(旧 Cloud Functions の後継)
  • Cloud Run の基盤上で動作
  • Eventarc / Pub/Sub / HTTP トリガ
シンプルな関数、Webhook、イベントハンドラ

Cloud Run リビジョン詳細

リビジョンとは

Cloud Run Service へのデプロイ・設定変更のたびに、イミュータブル(変更不可)なリビジョンが生成される。トラフィックを複数リビジョン間で分割できるため、canary / blue-green / A/B が標準機能で実現可能。

Cloud Run Service: my-api URL: https://my-api-xxx.a.run.app my-api-00001-abc image: app:v1 memory: 512Mi min-instances: 1 0% (前リビジョン) my-api-00002-def image: app:v2 memory: 512Mi min-instances: 1 90% (メイン) my-api-00003-ghi image: app:v3 memory: 1Gi tag: canary 10% (canary)
図1: 1つの Service に複数のリビジョン。各リビジョンに % でトラフィック配分。canary タグで固定 URL もアクセス可能。

traffic split のシナリオ別コマンド

# Step 1: 新リビジョンを 0% でデプロイ + canary タグ
gcloud run deploy my-api \
  --image=us-central1-docker.pkg.dev/PROJECT/repo/app:v2 \
  --no-traffic --tag=canary --region=us-central1

# Step 2: 10% に振る
gcloud run services update-traffic my-api \
  --to-tags=canary=10 --region=us-central1
# 監視 (Cloud Monitoring) で問題なければ拡大
gcloud run services update-traffic my-api --to-tags=canary=25 --region=us-central1
gcloud run services update-traffic my-api --to-tags=canary=50 --region=us-central1
gcloud run services update-traffic my-api --to-tags=canary=100 --region=us-central1
# canary=100 になると古いリビジョンは 0%、実質「全展開」完了
# 異常検知 → 即座に旧リビジョンに 100% 戻す
gcloud run services update-traffic my-api \
  --to-revisions=my-api-00001-abc=100 \
  --region=us-central1

# または LATEST タグで「直前」に戻す
gcloud run services update-traffic my-api \
  --to-revisions=LATEST=0 \
  --region=us-central1
# 任意の % 配分(複数リビジョン同時)
gcloud run services update-traffic my-api \
  --to-revisions=my-api-00001-abc=50,my-api-00002-def=30,my-api-00003-ghi=20 \
  --region=us-central1
# タグを付けると、固定 URL で特定リビジョンにアクセス可
gcloud run services update-traffic my-api \
  --set-tags=canary=my-api-00003-ghi,prod=my-api-00002-def \
  --region=us-central1

# 結果:
# - https://canary---my-api-xxx.a.run.app  → リビジョン v3
# - https://prod---my-api-xxx.a.run.app    → リビジョン v2
# トラフィック % とは独立した URL なので、A/B テスト用クライアントから明示的にどちらかにアクセス可能
自動ロールバックの本番運用パターン
  1. デプロイ: Cloud Build で --no-traffic --tag=canary でデプロイ
  2. 段階展開: 10% → Cloud Monitoring で error rate / p99 latency を観察
  3. SLO アラート: 5分間 error rate > 1% で Cloud Function を起動
  4. 自動ロールバック: Cloud Function が update-traffic --to-revisions=PREVIOUS_REV=100 実行
  5. 通知: Slack / Pub/Sub に通知
リビジョン管理の落とし穴
  1. 1 Service あたり最大 1,000 リビジョン。超えると古いリビジョンが自動削除される
  2. トラフィックを受けるリビジョンは削除不可。0% に下げてから削除
  3. min-instances=1 でリビジョンを残すと idle 課金が発生し続ける
  4. 環境変数を更新すると新リビジョンが作られる。誤って 100% を新リビジョンに振らないよう注意

Eventarc / Pub/Sub Push トリガ

Eventarc から Cloud Run を起動

gcloud eventarc triggers create my-trigger \
  --location=us-central1 \
  --destination-run-service=my-service \
  --destination-run-region=us-central1 \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=my-bucket" \
  --service-account=eventarc-trigger-sa@PROJECT.iam.gserviceaccount.com

主要なイベントタイプ

イベント用途
google.cloud.storage.object.v1.finalizedGCS にオブジェクトが置かれた
google.cloud.storage.object.v1.deletedGCS オブジェクト削除
google.cloud.pubsub.topic.v1.messagePublishedPub/Sub publish 検知
google.cloud.audit.log.v1.writtenCloud Audit Log 任意(最も柔軟)
google.cloud.firestore.document.v1.writtenFirestore 書き込み

Pub/Sub Push Subscription での起動

Pub/Sub Topic + Push Subscription push-auth-sa を指定 HTTP POST + JWT Authorization: Bearer xxx push-auth-sa の ID Token Cloud Run Service --no-allow-unauthenticated push-auth-sa に roles/run.invoker を付与 ⭐ JWT 検証は Cloud Run が自動 アプリでの検証コード不要
図2: Pub/Sub Push は push-auth-sa が JWT を発行 → Cloud Run が自動検証。
# 1. Cloud Run Service(認証必須)をデプロイ
gcloud run deploy my-handler --image=... --no-allow-unauthenticated --region=us-central1

# 2. Pub/Sub 用 SA 作成 + Cloud Run 呼び出し権限
gcloud iam service-accounts create cloud-run-pubsub-invoker
gcloud run services add-iam-policy-binding my-handler \
  --member=serviceAccount:cloud-run-pubsub-invoker@PROJECT.iam.gserviceaccount.com \
  --role=roles/run.invoker --region=us-central1

# 3. Pub/Sub サービスエージェントに Token 発行権限
PROJECT_NUMBER=$(gcloud projects describe PROJECT --format='value(projectNumber)')
gcloud projects add-iam-policy-binding PROJECT \
  --member=serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com \
  --role=roles/iam.serviceAccountTokenCreator

# 4. Push Subscription 作成
SERVICE_URL=$(gcloud run services describe my-handler --region=us-central1 --format='value(status.url)')
gcloud pubsub subscriptions create my-sub \
  --topic=my-topic \
  --push-endpoint=${SERVICE_URL}/push \
  --push-auth-service-account=cloud-run-pubsub-invoker@PROJECT.iam.gserviceaccount.com
Pub/Sub Push の落とし穴
  1. 2021/4/8 以前に作成されたプロジェクトでは、Pub/Sub サービスエージェントに roles/iam.serviceAccountTokenCreator明示的に付与する必要がある
  2. Cloud Run が 200/204 を返す前に処理を完了しないと再配信される
  3. Push subscription は at-least-once のみ。Exactly-once が必要なら Pull subscription に変更
  4. Cloud Run の HTTP timeout(最大 60分)を超える処理は Pub/Sub から再配信され続ける → 設計を見直す
  5. Push endpoint の URL に ?token=xxx のようなシークレットを URL に入れない(Pub/Sub のログに残る)
公式リファレンス Cloud Run + Pub/Sub Push / Eventarc overview

Cloud Run Jobs(バッチ処理)

HTTP リクエスト不要、最大 24時間、並列実行可能なバッチ実行環境。Cloud Run Service と同じ基盤だが用途が異なる。

# ジョブ定義
gcloud run jobs deploy my-batch \
  --image=us-central1-docker.pkg.dev/PROJECT/repo/batch:v1 \
  --region=us-central1 \
  --task-count=100 \              # 100 並列タスク
  --parallelism=10 \              # 同時実行は 10
  --max-retries=3 \               # 失敗時のリトライ
  --task-timeout=30m \            # 1タスクの最大時間
  --service-account=batch-sa@PROJECT.iam.gserviceaccount.com

# 実行
gcloud run jobs execute my-batch --region=us-central1 --wait

# 実行履歴
gcloud run jobs executions list --job=my-batch --region=us-central1

タスク並列化(CLOUD_RUN_TASK_INDEX)

# 各タスクが受け取る環境変数
import os

task_index = int(os.environ["CLOUD_RUN_TASK_INDEX"])     # 0, 1, 2, ... task_count-1
task_count = int(os.environ["CLOUD_RUN_TASK_COUNT"])     # 全タスク数
attempt = int(os.environ["CLOUD_RUN_TASK_ATTEMPT"])      # リトライ回数

# 例: 1000件のファイルを 100タスクに分散
files = list_files()
chunk_size = len(files) // task_count
my_files = files[task_index * chunk_size : (task_index + 1) * chunk_size]
for f in my_files:
    process(f)

Cloud Scheduler で定時起動

# 毎日深夜 2時に Cloud Run Job を起動
gcloud scheduler jobs create http my-nightly-batch \
  --schedule='0 2 * * *' \
  --time-zone='Asia/Tokyo' \
  --uri="https://us-central1-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/PROJECT/jobs/my-batch:run" \
  --http-method=POST \
  --oauth-service-account-email=scheduler-sa@PROJECT.iam.gserviceaccount.com \
  --oauth-token-scope=https://www.googleapis.com/auth/cloud-platform

Cloud Run Service を選ぶシーン

  • HTTP リクエストで起動
  • 処理時間 60分以内
  • 外部からのリクエストに応答

GKE CronJob を選ぶシーン

  • StatefulSet が必要
  • GPU 必須
  • K8s 既存資産の活用

Apigee による API 管理

Cloud Run / GKE の前段に置く、エンタープライズ API 管理プラットフォーム

機能ApigeeCloud API Gateway(軽量版)
OAuth2 / API キー認証
レート制限 / Quota✅ 細粒度✅ 基本
API バージョニング限定
API 収益化(Billing)
開発者ポータル
Analytics ダッシュボード限定
変換(Mediation)✅ XSLT、JS、Java callout
価格帯$$$ エンタープライズ$ 安い
典型ユースケースBtoB API、API as a Productシンプルな API ゲートウェイ
使い分けの判断軸
  • API を商品として売る」「開発者ポータル」「パートナーごとの収益化」 → Apigee
  • 軽量な API 認証 + ルーティング」「OpenAPI 仕様で運用」 → Cloud API Gateway
  • HTTPS 終端 + Cloud Run」だけなら、HTTP(S) Load Balancing のみで十分

3.2 GKE へのデプロイ

GKE Autopilot vs Standard 完全比較

Autopilot Google managed mode ✓ ノード管理は Google ✓ Pod 単位課金(リソース要求) ✓ デフォルトでセキュリティ強化 ✓ 自動アップグレード ✓ GPU / TPU / Arm 対応 ✗ 特権コンテナ制限 ✗ 一部 DaemonSet 制限 ✗ ノードカスタマイズ不可 推奨: 新規ワークロード Standard ユーザー管理ノード ✓ ノードプール / マシンタイプ自由 ✓ Spot VM 完全活用 ✓ カスタムカーネル / GPU ✓ Cluster Autoscaler 設定可 ✓ DaemonSet 自由 ✗ ノード課金(idle でも) ✗ アップグレード手動 / 計画必要 ✗ セキュリティ設定が手動 推奨: GPU・特殊要件
図3: Autopilot vs Standard の比較。新規は Autopilot、特殊要件は Standard。

選択フローチャート

Q1: GPU / TPU / Arm を使う?
YES → どちらも可だが Standard が柔軟
NO → Q2 へ
Q2: 特権コンテナ / カスタム DaemonSet が必要?
YES → Standard
NO → Q3 へ
Q3: ノードプール / マシンタイプを細かく分けたい?
YES → Standard
NO → Autopilot(推奨)
Autopilot の初回デプロイ遅延 Autopilot クラスタは 「starts with zero usable nodes」。最初のデプロイ時にノードのプロビジョニングが必要なため、数分の遅延がある。本番では事前にダミーワークロードを置く、または min replicas を設定。
公式リファレンス GKE Autopilot overview

Deployment / Service / Ingress / HPA の組合せ

インターネット Cloud Load Balancing Ingress (kind: Ingress) Service (kind: Service, type=ClusterIP / LoadBalancer / NodePort) selector で Pod を選び、kube-proxy で負荷分散 Deployment (kind: Deployment) replicas / template / strategy(RollingUpdate)/ HPA で動的スケール Pod 1 Pod 2 Pod 3 Pod 4 Pod 5 + HPA で動的
図4: GKE の階層。Ingress → Service → Deployment → Pod。LB は Ingress 作成で自動プロビジョニング。
# Deployment + Service + Ingress 一式
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels: { app: my-app }
  template:
    metadata:
      labels: { app: my-app }
    spec:
      serviceAccountName: my-ksa     # Workload Identity 用
      containers:
        - name: app
          image: us-central1-docker.pkg.dev/PROJECT/repo/app:v1
          resources:
            requests: { cpu: "100m", memory: "128Mi" }
            limits:   { cpu: "500m", memory: "256Mi" }
          ports:
            - containerPort: 8080
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /ready, port: 8080 }
            initialDelaySeconds: 5
            periodSeconds: 5
          startupProbe:
            httpGet: { path: /healthz, port: 8080 }
            failureThreshold: 30
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  type: ClusterIP
  selector: { app: my-app }
  ports:
    - port: 80
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    kubernetes.io/ingress.class: "gce"
spec:
  rules:
    - http:
        paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service: { name: my-app, port: { number: 80 } }

ヘルスプローブ 3種 — 役割と挙動

liveness Probe

  • 「Pod は生きているか?」
  • 失敗 → Pod を再起動
  • 過剰だと再起動ループ
/healthz 等の純粋な生存確認。外部依存を含めない。

readiness Probe

  • 「リクエストを受ける準備できた?」
  • 失敗 → Service エンドポイントから除外(再起動しない)
  • 初期化中・一時的な過負荷時の保護
/ready で外部依存(DB 接続)も確認

startup Probe

  • 「起動完了したか?」
  • 成功するまで liveness/readiness 開始しない
  • 重い初期化(JVM warm-up、ML モデル読み込み)に有用
failureThreshold × periodSeconds で起動時間を確保
0s 30s 60s 90s startup probe(起動中) liveness probe(startup 成功後に開始) readiness probe(並行) Service から除外(準備中) Service にトラフィック流れる
図5: 起動フローのタイムライン。startup 成功 → liveness/readiness 開始 → readiness OK で Service エンドポイント登録。
Probe の落とし穴
  1. liveness の path に DB 接続確認を入れる → DB 一時障害で Pod が全部再起動して連鎖障害
  2. readiness なし → 起動中の Pod にトラフィックが流れて 5xx 多発
  3. startup なしで initialDelaySeconds 長すぎ → liveness が成功するまで Pod が殺され続ける
  4. readiness の periodSeconds を長くしすぎ → 過負荷検知が遅れて雪崩

Horizontal Pod Autoscaler 深掘り

HPA のメトリクスタイプ

タイプ説明
ResourceCPU / メモリ使用率cpu: averageUtilization: 70
PodsPod 内のカスタムメトリックHTTP RPS(per pod)
ObjectKubernetes オブジェクトのメトリックIngress の RPS
Externalクラスタ外メトリックPub/Sub backlog、Cloud Tasks queue

Pub/Sub backlog で HPA(External Metric)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-worker-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-worker
  minReplicas: 2
  maxReplicas: 50
  metrics:
    - type: External
      external:
        metric:
          name: pubsub.googleapis.com|subscription|num_undelivered_messages
          selector:
            matchLabels:
              resource.labels.subscription_id: my-subscription
        target:
          type: AverageValue
          averageValue: "100"   # 1 Pod につき backlog 100 を目安
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300  # 5分間 idle 確認してから縮小

複数メトリクスの挙動

⚙️ HPA の判断ロジック
  • 複数メトリクス指定時、HPA は「最大値」を選択してスケール(最も Pod が必要な値)
  • いずれかのメトリクスが取得不能 → スケールアップは実行、スケールダウンは停止(安全側)
  • behavior で stabilizationWindowSeconds 設定 → 急激な変動を防ぐ
HPA の重要な制約と落とし穴
  1. HPA と VPA を CPU/メモリで併用しない(公式が明確に禁止)。Multidimensional Pod Autoscaling(beta)なら CPU=HPA / メモリ=VPA は可
  2. Pod の requests が未設定だと、Resource タイプの HPA が動かない
  3. DaemonSet は HPA 対象外(各ノードに1個固定)
  4. ReplicaSet ではなく Deployment に HPA を設定する
  5. External Metric の権限: GKE Workload Identity 経由で Cloud Monitoring API への読み取り権限が必要
公式リファレンス GKE HPA

GKE Workload Identity

GKE Pod から GCP API を呼ぶ標準パターン。Service Account Key の配布を不要にする。

Kubernetes Namespace KSA: my-ksa annotation: iam.gke.io/gcp-service-account Pod serviceAccountName: my-ksa アプリは ADC で自動認証 SA Key 不要 workloadIdentityUser GCP IAM GSA: my-gsa@PROJECT 通常の GCP サービスアカウント GCP API(GCS / BigQuery / etc.) roles/storage.objectViewer roles/bigquery.dataViewer
図6: KSA に annotation で GSA を紐付け。Pod は KSA を使い、自動的に GSA の権限で動作。

設定手順(必須3ステップ)

# 1. クラスタで Workload Identity を有効化
gcloud container clusters update my-cluster \
  --workload-pool=PROJECT_ID.svc.id.goog --region=us-central1

# 2. GCP SA 作成 + 権限付与
gcloud iam service-accounts create my-gsa
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member=serviceAccount:my-gsa@PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/storage.objectViewer

# 3. KSA 作成 + annotation + GSA 借用許可
kubectl create serviceaccount my-ksa
kubectl annotate serviceaccount my-ksa \
  iam.gke.io/gcp-service-account=my-gsa@PROJECT_ID.iam.gserviceaccount.com

gcloud iam service-accounts add-iam-policy-binding \
  my-gsa@PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:PROJECT_ID.svc.id.goog[default/my-ksa]"

Workload Identity vs Workload Identity Federation

Workload Identity Federation(GCP 外)

  • GitHub Actions / AWS / Okta から GCP API
  • OIDC / SAML プロバイダから連携
  • Pool / Provider / SA 借用
外部 IdP からの認証

🚨 事故ケース集(postmortem 形式)

デプロイ段階の設定ミスは本番障害に直結します。Cloud Run のリビジョン管理、GKE の Pod ライフサイクル、HPA のスケール挙動、Pub/Sub Push 統合は特に事故が頻発するエリアです。
CASE 3.1 GKE / Kubernetes Probe SEV-CRITICAL

liveness probe で DB 接続チェック → Cloud SQL 一時障害で全 Pod が再起動ループ、サービス全停止

▼ 症状

Cloud SQL の計画メンテナンス(30秒)が走った瞬間、サービス全体が応答不能に。自動復旧せず、メンテナンス終了後も復活しない。

▼ 原因
  • liveness probe のパスを /health にし、その中で「DB に SELECT 1 を投げる」実装
  • Cloud SQL の一時障害で DB クエリ失敗 → liveness 失敗 → Pod 再起動
  • すべての Pod が「DB 障害 → liveness 失敗 → 再起動 → またクエリ失敗」のループ
  • DB が復旧しても、各 Pod の起動時にも「DB 確認 + 失敗」を繰り返し、ループから抜け出せない
▼ 影響

本来 30秒で済むメンテナンスが、サービス全停止 22分に拡大。手動介入で復旧。

▼ 復旧手順
  1. 緊急で liveness probe を一時無効化(kubectl set で patch)
  2. すべての Pod が起動完了、Service エンドポイント復活
  3. liveness probe のパスを変更:DB 確認はreadiness probe に移し、liveness は純粋な生存確認のみ
▼ 予防策
  • liveness probe は外部依存を含めない(プロセス内の純粋な「生きている」チェックのみ)
  • DB 接続確認はreadiness probe で行う(失敗時は再起動せず、Service から除外のみ)
  • readiness が長時間失敗する場合は、PDB と組み合わせて部分的に降格
  • カオスエンジニアリングテストで「外部障害時の挙動」を事前検証
CASE 3.2 Cloud Run SEV-MEDIUM

過去リビジョンに min-instances=5 が残り続け、idle で課金が膨れ続けた

▼ 症状

Cloud Run の請求が想定の 3倍。Cost Explorer で見ると、稼働中の主要 Service ではなく「過去にデプロイしたテスト用 Service」が大きな割合を占めている。

▼ 原因
  • 負荷試験用に作成した Service で min-instances=5、メモリ 4Gi、CPU 2 を設定
  • 負荷試験終了後、その Service を削除し忘れていた
  • min-instances=5 のため、トラフィックが 0 でも 5インスタンスが永続稼働 → idle 課金
  • 料金的に CPU always-on モードで、毎月約 $500 の浪費
▼ 影響

3ヶ月で約 $1,500 の無駄な支出。発見が経理レビューで判明。

▼ 復旧手順
  1. 使用していない Service を gcloud run services delete で削除
  2. 残す Service は min-instances を見直し
▼ 予防策
  • テスト・実験用 Service にラベル environment=test を必須付与
  • 定期的に「不要なリソース」レポートを生成(Cloud Asset Inventory + BigQuery)
  • min-instances を高めに設定した Service はレビュー必須のガバナンス
  • Cost Anomaly Detection の Cloud Billing アラート設定
  • Service ごとにオーナーを定義し、四半期で棚卸し
CASE 3.3 GKE HPA SEV-HIGH

HPA の maxReplicas を 1000 に設定 → DDoS 攻撃でリソース枯渇 + 大量課金

▼ 症状

夜間に GKE クラスタが急成長、Pod 数が 1,000 に到達。Compute Engine の Quota が枯渇し新規 Pod が起動できない。Cloud Billing が前日比 8倍。

▼ 原因
  • HPA の maxReplicas=1000 と緩く設定
  • 外部攻撃者が DDoS 攻撃 → CPU 使用率が急上昇
  • HPA が「CPU 70%」をトリガーに Pod を増やし続け、上限の 1000 まで到達
  • ノードプールも追従して拡張 → ノードコストも爆増
  • Cloud Armor の WAF が前段に置かれていなかった
▼ 影響

夜間の数時間で約 $8,000 の追加課金。Cloud Quota 枯渇により正常リクエストも処理できず、SLA 違反。

▼ 復旧手順
  1. HPA の maxReplicas を 50 に下げる
  2. Cloud Armor の WAF を Cloud Load Balancing 前段に設定
  3. レートリミットルール(IP ベース)と Bot 検出を有効化
  4. 不正利用申告で課金免除を交渉
▼ 予防策
  • maxReplicas は過去ピーク負荷の 2〜3倍程度に現実的な上限
  • 本番では必ず Cloud Armor で WAF + レート制限
  • HPA の behavior でスケールアップ速度を制限(policies.value=100, periodSeconds=60
  • Pod のrequests を適切に設定し、Cluster Autoscaler 経由のノードコスト爆発を防ぐ
  • Cloud Billing Budget Alert で前日比 2倍を検知
CASE 3.4 Cloud Run + Pub/Sub Push SEV-HIGH

Cloud Run 処理が 60分超過 → Pub/Sub が再配信を続け、同じメッセージを無限処理

▼ 症状

注文処理が「重複処理されている」というユーザー苦情。ログを確認すると、同じ Pub/Sub メッセージが 20回以上配信されていた。

▼ 原因
  • 注文の決済処理が外部 API の遅延で 80分かかった
  • Cloud Run のリクエストタイムアウトはデフォルト 5分(最大 60分)
  • Cloud Run が 60分でタイムアウト → Pub/Sub には 5xx 相当が返る → 自動再配信
  • 再配信されたメッセージで同じ処理が再開(冪等でない実装) → 二重決済
  • これが何度も繰り返され「20回以上の再配信」発生
▼ 影響

顧客への二重課金 約 50件。返金処理 + 謝罪。CS 対応コスト数百万円。

▼ 復旧手順
  1. 長時間処理を Cloud Run Service から Cloud Run Jobs または Workflows に切り出し
  2. Cloud Run の HTTP ハンドラは「処理開始の記録」だけして即座に 200 を返す
  3. 処理の冪等性を確保(メッセージ ID または注文 ID で重複排除)
  4. Pub/Sub に Dead Letter Topic を設定し、再配信回数の上限を 5回に
▼ 予防策
  • Pub/Sub Push の受信処理は必ず冪等に実装(メッセージ ID で重複検知)
  • Cloud Run の HTTP timeout 内で完了しない処理は非同期化(Pub/Sub → Cloud Run Jobs / Workflows)
  • Dead Letter Topic を必ず設定(再配信回数上限を超えたら別 Topic へ)
  • Cloud Monitoring で「同一メッセージ ID の重複処理回数」のメトリックを監視
CASE 3.5 GKE Workload Identity SEV-MEDIUM

Workload Identity の annotation 設定漏れ → 「ノードのデフォルト SA」で動作し権限過多

▼ 症状

セキュリティチームから「Pod が本来不要な権限(roles/editor)で GCS にアクセスしている」と指摘。

▼ 原因
  • Pod の serviceAccountName: my-ksa を指定したが、Kubernetes ServiceAccount の annotation を忘れた
  • annotation iam.gke.io/gcp-service-account がないため、Workload Identity が機能しない
  • 結果、Pod はノードのデフォルト Compute Engine SAで動作(広い権限)
  • 動作はするので気づきにくい
▼ 影響

不要な権限による潜在的リスク。実害は未発生だが、規制要件の最小権限原則違反としてコンプライアンス指摘。

▼ 復旧手順
  1. KSA に annotation 追加:iam.gke.io/gcp-service-account=my-gsa@...
  2. GCP SA に roles/iam.workloadIdentityUser をバインド
  3. Pod 再起動 → ADC が GCP SA を使って動作することを確認
  4. ノードのデフォルト SA から不要な権限を剥奪
▼ 予防策
  • Workload Identity の構成を Terraform / Helm で自動化(手作業を排除)
  • Policy Controller / Gatekeeper で「KSA に annotation が必須」を強制
  • ノードのデフォルト SA から不要な権限を剥奪(最小権限)
  • Cloud Audit Logs で Pod 実行時の認証 SA を定期確認
CASE 3.6 GKE / Resource Requests SEV-HIGH

Pod の resources.requests 未設定 → 1ノードに Pod が過密スケジュールされ OOM 連鎖

▼ 症状

ピーク時間帯に Pod が次々と OOMKilled。kubectl describe では「memory pressure on node」のメッセージ。一部のノードに Pod が偏っている。

▼ 原因
  • Deployment の resources.requests を設定し忘れ
  • Kubernetes スケジューラは「Pod は無リソース要求」と解釈し、1ノードに過密配置
  • 実際にはアプリは大量のメモリを使う → ノードのメモリが枯渇
  • OOM Killer が Pod を殺す → 別ノードに再スケジュール → そこも過密 → OOM の連鎖
▼ 影響

サービス不安定 3時間。スケジューラのリバランス機能で自然復旧。SLO 違反。

▼ 復旧手順
  1. Deployment の resources.requestslimits を適切に設定
  2. VPA の Recommend モードで実測値ベースの推奨を取得
  3. Pod の再展開でスケジューラが正常配置
▼ 予防策
  • Kubernetes manifest の resources.requests必須化(Policy Controller でガード)
  • VPA を Recommend モードで導入し、適切な requests/limits を継続的に最適化
  • LimitRange を namespace に設定し、明示なし時のデフォルト値を強制
  • Autopilot を使えば requests 未設定でも自動補完される(事故予防)
CASE 3.7 GKE Node Pool SEV-HIGH

ノードプールの自動アップグレードで複数ノードが同時に drain → Pod 大量同時停止

▼ 症状

ノードプールアップグレード中、サービスが間欠的に 503 を返す。複数ノードが同時に drain され、Pod が大量に同時 terminate していた。

▼ 原因
  • Pod Disruption Budget (PDB) を設定していなかった
  • ノードアップグレードのデフォルト戦略は SURGE_UPGRADE で、複数ノードを並列処理
  • Deployment の replicas は 5 だったが、PDB なしのため複数 Pod が同時に terminate された
▼ 影響

アップグレード中 8分間、可用性 30%。SLO 違反。

▼ 復旧手順
  1. 緊急で PDB を追加し、再アップグレード
  2. Deployment の RollingUpdate の maxUnavailable を 1 に明示
▼ 予防策
  • すべての本番 Deployment に PDB を必須化(minAvailable=N-1)
  • Deployment の strategy.rollingUpdate.maxUnavailable を明示
  • ノードアップグレードのメンテナンスウィンドウを設定(業務時間外)
  • Surge upgrade の maxSurge=1, maxUnavailable=0 でゼロダウンタイム化
🎯 セクション3 事故ケースの学び デプロイ段階の事故は「設計時に検討しなかった非機能要件」から発生します。Probe の役割分担、PDB / requests / WAF / Idempotency などの「守りの仕組み」が欠けていると、些細な変動でも雪崩式障害になります。試験では「障害シナリオで何を設定しておくべきか」が問われます。

セクション3 試験戦略まとめ

🎯 24%を確実に取るためのポイント
  1. Cloud Run の 3形態: Services(HTTP)/ Jobs(バッチ)/ Functions(関数)
  2. リビジョン + traffic split: --no-traffic --tagupdate-traffic --to-tags
  3. Eventarc: GCP イベント駆動の標準。--event-filters="type=..."
  4. Pub/Sub Push: push-auth-sa + Cloud Run が自動 JWT 検証
  5. Cloud Run Jobs: HTTP 不要バッチ、最大 24時間
  6. Autopilot vs Standard: 新規 = Autopilot、GPU/特殊 = Standard
  7. Probe 3種: liveness(再起動)/ readiness(除外)/ startup(遅延開始)
  8. HPA External Metric: Pub/Sub backlog でスケール
  9. Workload Identity: GKE Pod から GCP API、SA Key 配布禁止
  10. Apigee: API 商品化・収益化、Cloud API Gateway は軽量版
問題文のキーワードと正解
  • 10% トラフィック」「段階的にロールアウト」 → Cloud Run + update-traffic --to-revisions=LATEST=10
  • HTTP 不要」「2時間のバッチ」 → Cloud Run Jobs + Cloud Scheduler
  • GCS にファイル up で起動」 → Eventarc
  • Pod が準備中で 5xx」 → readiness probe
  • Pub/Sub backlog で Pod スケール」 → HPA + External Metric
  • GKE Pod から GCP API、SA Key 配布禁止」 → Workload Identity
  • API 収益化・パートナーごとに課金」 → Apigee
  • 新規ワークロード、運用負荷最小」 → GKE Autopilot
  • GPU 必須」 → GKE Standard
📘 基礎 (MD) 🔧 応用 (MD) 🎯 要点と暗記 (MD)
← セクション2 セクション4 GCP統合 →