PCDE 合格対策
DEEP DIVE

🚀 CI/CD パイプライン徹底深掘り

Cloud Build / Cloud Deploy / Artifact Registry / SLSA / Binary Authorization / Software Delivery Shield の内部動作・制限値・事故ケース・運用ベストプラクティス・コスト落とし穴を、Google Cloud 公式ドキュメントベースで徹底解説します。試験対策の最終仕上げと、本番運用のリファレンスを兼ねた一枚教材です。

公式 docs 準拠 🎯 上級 ⚙️ 内部動作 📊 制限値表 ⚠️ 事故ケース 30+ 💰 コスト落とし穴
🎯 試験頻出 ⚠️ 事故ケース ✅ ベストプラクティス 📋 制限値 💰 コスト
🔑 TL;DR — このページの結論 Cloud Build は ephemeral VM × Docker container でステップを実行し、最大 24 時間 / 300 ステップ / 700 イメージまで。VPC 内の SQL や Private GKE に触るなら Private Pool 必須。Cloud Deploy は Pipeline → Target → Release → Rollout → Phase の 5 階層で、Skaffold が manifest を render → 各 target へ promote。canary は percentages: [25, 50] のように整数のみ。Artifact Registry は 1 プロジェクト・1 リージョン 60,000 req/min、ストレージ $0.10/GB/月、 0.5 GB まで無料。Binary Authorization は 1 プロジェクト 1 ポリシーREQUIRE_ATTESTATION + ENFORCED_BLOCK_AND_AUDIT_LOG が本番デフォ、本番投入前は必ず DRYRUN。SLSA L3 達成は 「ホスト型 + 署名付き provenance + run 間隔離 + 署名鍵分離」で Cloud Build が標準で満たす。Software Delivery Shield は Workstations → CSR/GitHub → Cloud Build → AR → AA → Binary Auth → Cloud Deploy → GKE/Run をエンドツーエンドで束ねる傘ブランド。
最大の事故源は SA キーの GitHub への流出(→ WIF へ移行)Binary Authorization breakglass の常用化Artifact Registry のリージョン跨ぎ pull コストCloud Build default pool で SQL に届かず謎の hangcleanup policy 未設定で AR ストレージ青天井の 5 つです。

📚 参照する公式ドキュメント

本資料は以下の Google Cloud 公式ドキュメント(2026 年時点)から技術詳細・制限・SLA・ベストプラクティスを抽出しています。各章で都度引用と URL を併記します。

1Cloud Build 徹底解剖

Cloud Build は ephemeral VM の上で各ステップを Docker コンテナとして直列/並列実行する、サーバーレス CI 基盤です。試験では「Default Pool vs Private Pool」「substitutions の落とし穴」「Secret Manager 連携」「machineType の選定」「並列実行制御」「SLSA L3 自動付与」がほぼ必ず問われます。

「Cloud Build sets up a new virtual machine environment for every build and destroys it after the build.」 — Cloud Build overview

1.1 アーキテクチャ — トリガーからイメージ push までの内部動作

Trigger Source GitHub / GitLab Pub/Sub / Webhook Cloud Build Controller trigger 評価 → Build 作成 substitution 解決 Build Scheduler Pool 選択 / quota チェック VM 払い出し Artifact Registry image push auto SLSA provenance 🖥️ Ephemeral Worker VM(ビルドごとに作成→破棄) Docker network: cloudbuild /workspace 共有 Volume 全 step で共有・persist step 1: install name: node:20 npm ci id: install (serial) step 2: test npm test waitFor: [install] step 3: build docker build + --cache-from Secret Manager availableSecrets Build SA user-specified SA 推奨 Cloud Logging / Cloud Storage(logsBucket / defaultLogsBucketBehavior) CLOUD_LOGGING_ONLY / GCS_ONLY / LEGACY / NONE
図 1-1:Cloud Build の内部アーキテクチャ。トリガー → Controller → Scheduler → ephemeral VM 払い出し → Docker network 上で各ステップを順次/並列実行 → AR へ push + provenance 自動生成。ステップ間は /workspace ボリュームと cloudbuild Docker network で連携。
🔑 内部動作の重要ポイント
  • 各ステップは Docker コンテナとして独立に起動(Docker 20.10.24)。OS / バイナリの差異はビルダーイメージで吸収。
  • VM はビルドごとに新規作成・終了後破棄。前回ビルドの状態は残らない(→ キャッシュは別途設計)。
  • ステップ間の 状態共有は /workspace のみ。$HOME や他ディレクトリは次ステップに引き継がれない。
  • 並列実行は waitFor: ['-'](依存なし=即時開始)または特定 step ID 配列で制御。
  • イメージ push は images: に書けば 成功時に Cloud Build が自動 push(自前 docker push ステップ不要)。

1.2 cloudbuild.yaml 完全リファレンス(公式 schema 準拠)

steps: # 必須。最大 300 step - name: 'gcr.io/cloud-builders/docker' # 必須。builder image id: 'build' # 任意。waitFor の参照用 entrypoint: 'bash' # builder image の ENTRYPOINT 上書き args: ['-c', 'docker build .'] # 最大 100 args / 各 10,000 char env: ['NODE_ENV=production'] # step スコープ環境変数(最大 100、各 65,536 char) secretEnv: ['DB_PASS'] # Secret Manager 由来の機密 env dir: 'subdir' # /workspace/subdir で実行 timeout: '600s' # step 単位タイムアウト waitFor: ['install', 'test'] # 依存 step ID('-' で並列開始) volumes: # 任意 mount(複数 step で共有可) - name: 'cache' path: '/cache' allowFailure: true # 失敗してもビルド全体は成功 allowExitCodes: [0, 1, 2] # allowFailure より優先、許容 exit code script: | # args/entrypoint と排他、シェルスクリプト直書き echo "hello" availableSecrets: # Secret Manager 由来の secret を宣言 secretManager: - versionName: projects/PROJECT/secrets/db-pass/versions/latest env: 'DB_PASS' # ← steps[].secretEnv で参照 images: # 成功時に自動 push される Docker image - 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/repo/app:$SHORT_SHA' artifacts: # 非 Docker 成果物 objects: { location: 'gs://my-logs/build/$BUILD_ID', paths: ['report/*.html'] } mavenArtifacts: [...] pythonPackages: [...] npmPackages: [...] goModules: [...] substitutions: # ユーザー定義は _ で始める(最大 200) _ENV: 'dev' _REGION: 'asia-northeast1' tags: ['app=myapp', 'env=dev'] # 最大 64 timeout: '1800s' # ビルド全体(default 60min, max 24h) queueTtl: '3600s' # キュー待ち最大(default 1h) logsBucket: 'gs://my-logs-bucket' serviceAccount: 'projects/PROJECT/serviceAccounts/builder@PROJECT.iam.gserviceaccount.com' options: machineType: 'E2_HIGHCPU_8' # vCPU/Memory 増強 diskSizeGb: 200 # 最大 4000 GB logging: CLOUD_LOGGING_ONLY # GCS_ONLY / CLOUD_LOGGING_ONLY / LEGACY / NONE logStreamingOption: STREAM_ON # STREAM_OFF / STREAM_ON substitutionOption: ALLOW_LOOSE # MUST_MATCH(未参照 var で fail)/ ALLOW_LOOSE dynamicSubstitutions: true # bash パラメータ展開 ${var/foo/bar} を有効化 automapSubstitutions: true # 全 substitution を自動的に env 化 requestedVerifyOption: VERIFIED # ← SLSA L3 provenance 生成 defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET pool: # Private Pool 指定 name: 'projects/PROJECT/locations/asia-northeast1/workerPools/my-pool' env: ['CI=true'] # 全 step の env pubsubTopic: 'projects/PROJECT/topics/build-notify'
▶ 主要フィールドの詳細解説(クリックで展開)
steps[].name
使用するビルダーコンテナイメージ。gcr.io/cloud-builders/* の公式 builder か、任意の Docker Hub / AR / OCI image。
steps[].entrypoint
image の ENTRYPOINT を上書き。docker builder で bash -c を使う際によく指定。
steps[].waitFor
['-'] で依存なし=即並列開始、['install'] で install step 完了後に開始。未指定は直前 step に直列
steps[].allowFailure / allowExitCodes
テスト失敗を吸収して後続 step を走らせたい場合。allowExitCodes が優先される。
steps[].script
args/entrypoint と排他。インラインシェルスクリプト。改行をそのまま書ける。
availableSecrets
Secret Manager version を env name に bind。step の args 内で $$VAR として参照(シェルが展開する $1 段階)。
images
ビルド成功時に Cloud Build が自動 push する Docker image 一覧。最大 700。明示 docker push 不要。
artifacts
GCS への汎用ファイル / Maven / Python / npm / Go module 成果物。Docker image は images: 側。
options.machineType
UNSPECIFIED(e2-medium, 1vCPU/4GB) / E2_HIGHCPU_8/32 / N1_HIGHCPU_8/32 / E2_STANDARD_2/4 / C2_STANDARD_8 / C2D_STANDARD_16 など。Private Pool では更に多くの選択肢。
options.requestedVerifyOption: VERIFIED
SLSA L3 provenance を自動生成・署名。CMEK 利用や Provenance 要件のあるパイプラインで必須。
options.substitutionOption
MUST_MATCH=未定義/未参照 substitution があると build fail(安全)、ALLOW_LOOSE=寛容モード(事故源)。
queueTtl
キュー待ち時間の上限(既定 1h)。同時実行 quota 不足で長時間待つ場合に expire される。
serviceAccount
build 実行に使う SA。本番では必ずユーザー指定 SAを使う(legacy default の PROJECT_NUMBER@cloudbuild.gserviceaccount.com は権限が広すぎ)。

1.3 マシンタイプ別性能と料金(per-minute)

machineTypevCPUMemoryper-minute (USD)1 ビルド 10 分の料金用途
UNSPECIFIED / E2_MEDIUM14 GB$0.003$0.03軽量 CI、無料枠 120 分/日内
E2_STANDARD_228 GB$0.006$0.06標準 web app ビルド
N1_HIGHCPU_8 / E2_HIGHCPU_887.2-8 GB$0.015-0.016$0.15-0.16並列 npm/maven、Docker build 高速化
N1_HIGHCPU_32 / E2_HIGHCPU_323228.8-32 GB$0.032$0.32大規模 monorepo、並列テスト
C2_STANDARD_8 (Compute Opt.)832 GB$0.030$0.30CPU 律速のコンパイル(Rust/C++)
C2D_STANDARD_161664 GB$0.060$0.60巨大 Java/Scala build、AVX-512 系
120 min/日
無料枠(e2-medium 換算)
$0.003/分
最安 (e2-medium)
24 時間
最大 timeout
無料
Ingress(egress は標準料金)
💰 コスト落とし穴 — 「速い=安い」の罠 e2-medium で 30 分かかるビルドを E2_HIGHCPU_8 で 5 分に短縮すると、$0.09 vs $0.075 で実は 後者の方が安い。マシンタイプ選定は「単価 × 所要分数」で比較すること。一方で 1 vCPU で十分な軽量ビルドを HIGHCPU_32 で回すと無駄に 10 倍コストになるので、並列度・コンパイルの CPU バウンド性を見極めること。

1.4 Default Pool vs Private Pool 完全比較

比較軸Default PoolPrivate Pool
ネットワークパブリック IP のみ・VPC 不可VPC peering で内部 IP に到達可
同時ビルド数(quota)10-30 (global)最大 100+ / region(C3/E2/N2D 各 2400 vCPU まで)
マシンタイプ数5 種64 種(E2/N1/N2/N2D/C2/C3/C3D 等)
静的 outbound IP不可可(NAT で固定)
Public IP 無効化不可可(完全 private)
料金モデルper-minute(無料枠 120 min/日)per-minute(無料枠なし、別単価)
セットアップ不要Worker Pool 作成 + VPC peering 設定
クロスプロジェクト build不可IAM 設定で可
主な用途OSS/一般 web appPrivate GKE / Cloud SQL Private IP / 内部 API / コンプライアンス
🚨 試験頻出 — 「Private Pool が必要」のシグナル 問題文に 「Cloud SQL を Private IP のみで運用」「Private GKE クラスタ」「on-prem の Active Directory に LDAP 認証」「VPC SC 境界内のリソースにアクセス」のいずれかが出てきたら、Private Pool 一択。Default Pool では VPC 内に到達できず、ビルドが timeout で謎の hang を起こす(10/30 並列を食い潰す事故の代表例)。

1.5 Worker Pool の VPC 接続パターン(SVG)

Google Service Producer VPC (Cloud Build が管理・非公開) Worker Pool ephemeral Worker VMs Cloud NAT (任意) 静的 outbound IP VPC Peering --peered-network Customer Shared VPC (自社管理) Private GKE Cluster (control plane) Cloud SQL (Private IP) Internal HTTPS LB / 内部 API + on-prem へは Interconnect / VPN gcloud builds worker-pools create my-pool --peered-network=...
図 1-2:Private Pool の VPC 接続。Google 側 producer VPC と顧客 Shared VPC を peering することで、ビルド VM が Private IP のみで運用される GKE/Cloud SQL/内部 LB に直接到達できる。Cloud NAT を併用すれば 固定 outbound IP も実現可能(外部 API のホワイトリスト対応)。

1.6 Cloud Build 制限値(公式 quotas より)

項目制限値備考
同時ビルド数(Default Pool, global)10–30region/CPU により可変。上限申請可
Concurrent E2 CPUs (Default, region)5–100申請で増加可
Concurrent CPUs (Private Pool, region)最大 2400(E2/N2D), 300 (C3)region per machine family
ステップ数(steps)/ build300固定
image 数 / build700固定
args 数 / step100各 arg 最大 10,000 文字
env 数 / step100各 env 最大 65,536 文字
substitution 数200ユーザー定義は _ 始まり必須
tags / build64
build triggers / project600固定
secret サイズ65,536 文字
build timeout最大 24 時間default 60 分
queueTtldefault 3,600 秒キュー待ちで expire
diskSizeGb最大 4,000 GBoptions.diskSizeGb
step 名長1,000 文字

1.7 ⚠️ Cloud Build 事故ケース集

事故 1:Default Pool で Private GKE control plane に届かず、毎回 timeout でビルド枠を食い潰す
症状build step kubectl applyi/o timeout、Default Pool 10/10 並列が常時 hang。他チームのビルドも全部 stuck。
原因Private GKE クラスタは control plane が Private IP のみ公開、Default Pool は公開インターネットからしか到達できない。
対処① Private Pool を作成し --peered-network で Shared VPC に peering ② options.pool.name で指定 ③ 過去の hang build は gcloud builds cancel
予防「Private GKE / Cloud SQL Private IP / VPC SC 境界内」と要件出た瞬間に Private Pool に倒す。CI 設計時に必ず確認するチェックリスト化。
事故 2:Secret Manager の値がビルドログに平文出力
症状DB パスワードが Cloud Logging に丸見え、組織監査で指摘される。
原因availableSecrets で受け取った値を echo "$$DB_PASS" で出力していた / set -x を有効にしていた。
対処① 該当ログを logging exclusion filter + Cloud Storage バケット側で削除 ② Secret を即 rotation(旧値は漏洩済として扱う) ③ build step スクリプトを修正。
予防secret は secretEnv 経由のみ・set +x をスクリプト先頭で実行・echo 禁止のレビュールール化。
事故 3:substitutionOption: ALLOW_LOOSE で _REGION typo が production に流出
症状_REGON と typo した substitution が空文字に展開されイメージ URL が壊れた状態で push、後続 deploy で異常検知。
原因options.substitutionOption: ALLOW_LOOSE により未定義変数も warning だけで通過。
対処MUST_MATCH(既定)に戻す ② すべての substitution 参照を grep でレビュー ③ pre-commit で gcloud builds submit --no-source --dry-run 風の lint。
予防ALLOW_LOOSE は禁止。本番 config は MUST_MATCH 固定。
事故 4:Docker layer cache 無し / .gcloudignore 未設定で毎ビルド 800 MB アップロード
症状1 行コード変更でもビルドが 12 分、月間 Cloud Build 課金が想定の 5 倍。
原因node_modules/, .git/, dist/ を含めてソースをアップロード ② docker build --cache-from 未指定で毎回フル再ビルド。
対処.gcloudignore 作成 ② Kaniko or --cache-from でレイヤキャッシュ ③ multi-stage Dockerfile で依存層と app 層を分離。
予防新規 repo セットアップ時のテンプレに .gcloudignore を含める。
事故 5:Private Pool の Concurrent CPU quota 枯渇で全社デプロイ凍結
症状金曜夕方の一斉リリースで Private Pool の同時 build が 100 を超え、後続が全部 queueTtl で expire。
原因Private Pool は per-region CPU quota(既定 0、申請ベース)。チーム成長で実態が quota を超過。
対処① IAM Admin で quota 増加申請 ② machineType を見直して 1 build あたり消費 vCPU を圧縮 ③ build 時間帯を分散。
予防Monitoring で cloudbuild.googleapis.com/build/activequota 80% で alert
事故 6:waitFor の依存ミスで test 実行前に Docker push、壊れた image が AR に残存
症状test が落ちる前に「成功扱い」で image が push され、cleanup されない壊れた image が AR を圧迫。
原因images:step の成否に関わらず最後に push される設計。test step が allowFailure: true だと build 自体は成功扱い。
対処allowFailure を外し、test 失敗で build を fail させる ② AR 側 cleanup policy で UNTAGGED + olderThan: 7d を削除 ③ tag を $SHORT_SHA 固定にして上書きを防ぐ。
事故 7:legacy default SA を使い続けて重大な権限昇格穴
症状build trigger を作る権限を持つ全員が、Secret Manager の本番 secret に間接アクセス可能だった。
原因PROJECT_NUMBER@cloudbuild.gserviceaccount.com は project Editor 相当に近い権限を持つ。
2024 年以降の新 project では default が変わったが、旧 project は引き続き昔の SA が現役。
対処serviceAccount field でユーザー指定 SA に明示移行(必要権限だけ付与) ② trigger ごとに --service-account を指定 ③ legacy SA への role binding を削除。
事故 8:queueTtl デフォ 1h で深夜のリトライ jobs が全 expire
症状翌朝出社したら nightly build が全 expire、テスト結果が無い状態に。
原因同時実行 quota 不足で大量にキュー、queueTtl: 3600s(既定)で順番に expire していた。
対処queueTtl を長めに(24h まで設定可) ② quota 増加 ③ jobs を時間帯分散。

1.8 ✅ Cloud Build ベストプラクティス 10 項目

  1. 本番は user-managed SA を必須化serviceAccount field を指定し、Secret Manager / Artifact Registry / GKE に必要な最小権限のみ付与。
  2. WIF で外部 CI と連携:GitHub Actions / GitLab CI から Cloud Build を呼ぶときは SA キー禁止、Workload Identity Federation で OIDC trust。
  3. Private GKE/SQL/内部 API なら Private Pool:Default Pool で hang する前に必ず Pool 設計。
  4. substitutionOption: MUST_MATCH:typo を build 時に検知させる。ALLOW_LOOSE は絶対禁止。
  5. .gcloudignore を必ず作成node_modules/, .git/, dist/, .terraform/ を除外。アップロード時間とコストを劇的に削減。
  6. Docker layer cache を有効化:Kaniko (gcr.io/kaniko-project/executor) または docker build --cache-from。依存層が変わらない限り再 build スキップ。
  7. multi-stage Dockerfile:build stage(重い)と runtime stage(軽い)を分離、最終 image を distroless / Alpine ベースに。
  8. machineType は「単価×時間」で選定:軽量 = e2-medium、CPU バウンドコンパイル = C2/C2D、メモリ多用 = N2_HIGHMEM。
  9. secretEnv 一択・ログ漏洩防止availableSecrets 以外で機密を扱わない、set +x 強制、Cloud Logging に exclusion filter。
  10. SLSA L3 を素直に取りに行くoptions.requestedVerifyOption: VERIFIED と user-managed SA で Cloud Build は自動的に L3 相当の provenance を生成。Binary Authorization と接続して built-by-trusted-builder ポリシーを enforce。

2Cloud Deploy 徹底解剖

Cloud Deploy は Skaffold をエンジンに用いた managed Continuous Delivery 基盤です。GKE / Cloud Run / GKE Enterprise への promotion ベースの段階的リリースcanary / blue-green / standard 戦略Verification / Predeploy / Postdeploy hooksApproval gateRollback を宣言的に管理します。試験では「Pipeline / Target / Release / Rollout / Phase の階層」「canary phase percentage」「Skaffold rendering の内部動作」「multi-target promotion」「approval timeout」「automation」が頻出。

「A delivery pipeline is the top-level Cloud Deploy resource. A release represents a logical version of the application, and a rollout deploys that release to a single target.」 — Cloud Deploy overview

2.1 リソース階層と関係(Pipeline / Target / Release / Rollout / Phase)

📜 Delivery Pipeline(宣言的 YAML、リージョナル) serialPipeline.stages = [dev → staging → prod]、deployParameters、suspended、各 stage に strategy 1 pipeline = 1 app / 1 region、複数 pipeline で multi-region・multi-tenant 🎯 Target: dev gke: cluster, namespace requireApproval: false executionConfigs[].usages: RENDER+DEPLOY 🎯 Target: staging multiTarget.targetIds: [stg-us, stg-eu] requireApproval: false parallel deploy 🎯 Target: prod run: location, project requireApproval: true canary 25 → 50 → 100 📦 Release(不変、Skaffold render snapshot を保持) gcloud deploy releases create v1-2-3 --images app=...:sha256:... 作成時に skaffold が 各 target 用 manifest を一括 render → GCS に snapshot、以後 promotion 中も不変 🚀 Rollout (dev) strategy: standard Phase: stable (100%) 🚀 Rollout (staging) strategy: standard, multi-target parallel Phase: stable 🚀 Rollout (prod) strategy: canary 25/50 Phase: canary-25 → canary-50 → stable ⚙️ Job(Phase 内の最小実行単位) predeploy → deploy → verify → postdeploy(各 Job は Cloud Build 上で skaffold を実行) promote promote
図 2-1:Cloud Deploy の 5 階層リソース。Pipeline(不変宣言)→ Target(環境)→ Release(render snapshot、不変)→ Rollout(target ごとに 1 つ)→ Phase(canary/stable 等)→ Job(predeploy/deploy/verify/postdeploy)。promotion は左から右に gcloud deploy releases promote で進む。
🔑 階層を一文で覚える 「Pipeline 1 個に Target N 個。Release は不変 snapshot、Rollout は Target ごと、Phase は Canary 内の段階、Job は Phase 内のステップ」。試験で「rollback はどの単位?」と問われたら Rollout 単位gcloud deploy rollouts rollback)。「manifest はいつ render される?」と問われたら Release 作成時

2.2 delivery-pipeline.yaml / target.yaml 完全例

# delivery-pipeline.yaml(canary戦略 + verification + approval + multi-target) apiVersion: deploy.cloud.google.com/v1 kind: DeliveryPipeline metadata: name: app-pipeline description: web app pipeline serialPipeline: stages: - targetId: dev profiles: [dev] # skaffold profile strategy: { standard: { verify: true } } - targetId: staging-multi # multi-target profiles: [staging] strategy: standard: verify: true predeploy: { actions: ['action-smoke-test'] } postdeploy: { actions: ['action-notify'] } - targetId: prod profiles: [prod] strategy: canary: runtimeConfig: kubernetes: serviceNetworking: service: app-svc deployment: app disablePodOverprovisioning: false canaryDeployment: percentages: [25, 50] # ← 整数のみ、最大 5 phase、最後の 100 は自動付与 verify: true predeploy: { actions: ['action-canary-warmup'] } postdeploy: { actions: ['action-canary-bake'] } --- # target.yaml — multi target apiVersion: deploy.cloud.google.com/v1 kind: Target metadata: { name: staging-multi } multiTarget: targetIds: [staging-us, staging-eu] # 並列デプロイ --- apiVersion: deploy.cloud.google.com/v1 kind: Target metadata: { name: prod } requireApproval: true # ← 承認ゲート gke: cluster: projects/PROD/locations/asia-northeast1/clusters/prod executionConfigs: - usages: [RENDER, DEPLOY, VERIFY, PREDEPLOY, POSTDEPLOY] workerPool: projects/PROD/locations/asia-northeast1/workerPools/cd-pool serviceAccount: cd-runner@PROD.iam.gserviceaccount.com artifactStorage: gs://prod-cd-artifacts executionTimeout: 3600s # 既定 1h、最大 24h deployParameters: { ENV: production, REPLICAS: "10" }

2.3 Skaffold + Kustomize + Helm 統合の内部動作

Cloud Deploy は Skaffold をレンダリングエンジンとして組み込み、Release 作成のタイミングで 1 度だけ各 target 向け manifest を生成 → GCS に snapshot します。Rollout 実行時はもう一度 render はしない(既に snapshot 済の manifest を kubectl apply / gcloud run deploy するだけ)。これにより 「dev で render したものと prod で render したものが違う」事故を構造的に排除しています。

skaffold.yaml manifests: kustomize / helm / raw profiles: dev/stg/prod gcloud deploy releases create --images app=...:sha256:... → skaffold render (per target) → image digest を pin GCS Snapshot target=dev/manifest.yaml target=stg/manifest.yaml target=prod/manifest.yaml Rollout snapshot を kubectl apply (再 render しない) ⚠️ 重要:image は必ず digest (sha256) で pin される --images フラグは app=asia-northeast1-docker.pkg.dev/p/r/app:1.2.3 のように tag でも 指定可だが、Cloud Deploy が内部で digest を解決して manifest に焼き込むため、 後から同じ tag に別の image が push されても Release 内容は不変。 → promotion / rollback の再現性が完全に保証される(SLSA L3 の Hermetic 要件にも整合)
図 2-2:Release 作成時に skaffold が全 target 分の manifest を一括 render → GCS snapshot → 以後 Rollout は snapshot を再生するだけ。image は digest で pin。

2.4 Canary 戦略の詳細(Phase / Verification / Hooks)

項目仕様備考
percentages整数のみ [1-99]、最大 5 要素最後の 100 は自動付与(stable phase)
phase 命名canary-25, canary-50, stable自動生成
verify各 phase 後に skaffold verify を実行失敗時は自動で Rollout が halt(手動 retry/rollback)
predeploy / postdeploy hooks各 phase の前後で任意 action 実行warmup、smoke test、通知、外部チェック等
canary 推進gcloud deploy rollouts advance自動 or 手動。automation で自動化可
kubernetes 実装Service / Deployment ベースで pod 比率を切替Pod Overprovisioning で旧 ver を一時保持
Cloud Run 実装Traffic split で revision 比率を切替--traffic ベース、瞬時切り替え
Gateway API canaryHTTPRoute weight で精密制御GKE Gateway 利用時、Istio 不要
💡 ベストプラクティス — Canary 設計
  • percentages: [10, 50] が最も使われるパターン。10% で実害を最小化、50% で「ピーク負荷で問題が出るか」を確認、その後 100%。
  • 各 phase で verify: true を必須化。verify が無いと canary は「ただの遅い 100% deploy」
  • verify には SLO ベースのチェック(error rate < 1%, p99 latency < 200ms)を入れる。Cloud Monitoring metrics を取得する skaffold custom action で実装。
  • postdeploy hook で baking 時間(例: 10 分待ってから次 phase)を入れて、metrics が安定するのを待つ。

2.5 Multi-target / Parallel Deployment / Promotion フロー

1 つの logical target 内に複数の child target を束ねる multi-target を使うと、同一 release を 並列に複数 region / cluster へデプロイできます。例えば「staging US と staging EU を同時に展開して両方で smoke test」「prod も asia / us / eu の 3 region に並列展開」など。

# Multi-target target.yaml apiVersion: deploy.cloud.google.com/v1 kind: Target metadata: { name: prod-multi } requireApproval: true multiTarget: targetIds: [prod-asia, prod-us, prod-eu] # 並列デプロイ deployParameters: { ENV: production } # Rollout は multi-target に対して 1 つだが、内部で children rollouts が並列実行 # gcloud deploy rollouts describe で child の進捗を確認 gcloud deploy rollouts describe ROLLOUT_NAME \ --release=RELEASE --delivery-pipeline=PIPELINE --region=REGION

2.6 Cloud Deploy 制限値(公式 quotas より)

項目制限値備考
Delivery pipelines / project / region1,000
Targets / project / region1,000multiTarget も 1 つとしてカウント
Stages / pipeline20serialPipeline.stages の最大長
Child targets / multiTarget10並列実行の最大数
Canary phases5percentages 配列の最大長(+ stable 自動付与)
Release 保持期間無期限手動削除まで GCS snapshot が残存(コスト注意)
Rollout queue 長1 rollout / target同時に 2 つは走らせられない
Approval timeout既定 無期限放置すると Rollout が永久に pending
executionTimeout既定 1h / 最大 24hrender / deploy / verify の各 Job 単位
verifyTimeout既定 1h / 最大 24h
Automations / pipeline250auto-promote / auto-rollback / repair など
Job runs 履歴保持14 か月Cloud Audit Logs と別管理
💰 料金モデル Cloud Deploy 自体は $0.05 / deploy(最初の 30 deploy/month 無料)。実際の重コストは Cloud Build (render / verify) の実行時間GCS の release snapshot 保管。長期間の Release を放置すると GCS バケットが肥大化するので、不要な Release は gcloud deploy releases abandon + 古い snapshot の lifecycle 設定で対処。

2.7 ⚠️ Cloud Deploy 事故ケース集

事故 1:approval timeout が無いため、休暇中の承認待ちで prod release が 2 週間凍結
症状承認者が休暇 → 後続 Rollout が pending のまま、新しい Release も作れず(同じ target で 2 つは走らない)。
原因Cloud Deploy には標準で approval timeout が無い。requireApproval: true は無期限待機。
対処① 承認権限を 複数人(group)に付与 ② Automation で「24h 経過した approval は自動 reject + Slack 通知」を実装 ③ 休暇前は承認権限を delegate
予防本番 approval ロールはチーム全員に与えず、当番制 + バックアップ承認者 2 名以上。
事故 2:canary verification 失敗時に自動 rollback されず、25% のユーザーがエラーを浴び続ける
症状canary-25 phase で verify が落ちたが、新トラフィックは 25% に流れたまま、エラー率が急上昇。
原因verify 失敗は Rollout を halt するだけで自動 rollback はしないのが既定。手動で gcloud deploy rollouts rollback が必要。
対処① 即座に rollouts rollback 実行 ② Automation の auto-rollbackkind: Automation with rollback rule)を設定 ③ verify には SLO baseline + alert を含める。
予防「verify 失敗 = 自動 rollback」をデフォルト設計に。Pipeline 作成時テンプレ化。
事故 3:Skaffold image rendering ミス — tag のまま push されて再現性喪失
症状Release 作成後に同じ tag (:latest) に別の image を push、prod に意図しない image がデプロイされた…と思いきや、実際にデプロイされたのは Release 作成時の digest。テストが過去 image を見ていただけ。
原因Cloud Deploy は image を digest で pin するため :latest push は影響しないが、開発者が CLI で kubectl get pods した時に「あれ?image が古い」と混乱した。
対処① そもそも :latest を禁止 ② tag を $SHORT_SHAvX.Y.Z で immutable に ③ Artifact Registry の Tag Immutability を有効化。
事故 4:multi-target で 1 region だけ deploy 失敗、他は成功 → 一貫性破綻
症状asia / us / eu の multi-target で eu のみ quota エラーで失敗、asia/us は新 version 動作中で「version skew」が発生。
原因multi-target は independent parallel deploy。1 つ失敗しても他はロールバックされない。
対処① 失敗 child を 個別に retry ② Automation で「multi-target のどれか失敗 = 全 region rollback」を実装 ③ region 間 schema 互換性を予め設計(backward compatible migration)。
事故 5:custom Worker Pool の SA 権限不足で render は通るが deploy で 403
症状dev/staging では正常に動いた pipeline が prod でだけ permission denied on cluster
原因prod target の executionConfigs.serviceAccount が GKE cluster admin 権限を持っていなかった。
対処① CD runner SA に roles/container.developer + namespace 単位の RBAC を付与 ② roles/clouddeploy.runner を SA に付与 ③ usages リストに RENDER/DEPLOY/VERIFY を全部入れる。
事故 6:Release を消したら Rollout 履歴も消えて監査時に説明できない
症状古い release を整理しようと delete したら、関連 Rollout の詳細(誰がいつ promote したか)が UI から消えた。
原因Release は Rollout のメタを保持する親リソース。delete すると child Rollout も消える。Cloud Audit Logs は別途残るが UI 経由では追跡不可。
対処① delete 前に Cloud Audit Logs をエクスポート ② 整理は delete でなく gcloud deploy releases abandon(meta は残る) ③ GCS lifecycle で snapshot バケットだけ古いものを削除。
事故 7:deployParameters の typo で prod に dev DB が向いた
症状prod に staging DB の接続文字列が注入され、prod traffic が staging DB を圧迫。
原因Pipeline / Target の deployParameters が階層的にマージされる際、Target 側の overrride が無く Pipeline 側の dev 値が使われた。
対処① 環境固有値は必ず Target 側 deployParameters で override ② Skaffold profile を環境ごとに完全分離 ③ render 後の manifest を CI で diff チェック。

2.8 ✅ Cloud Deploy ベストプラクティス 10 項目

  1. 1 app = 1 pipeline:複数 app を 1 pipeline に詰め込まない。リリースサイクルが結合してしまう。
  2. image は必ず digest で pin--images 渡し時 tag でも digest に解決されるが、CI 側で digest 取得して明示渡しが最も安全。
  3. canary は最低 [10, 50]、verify 必須:1 phase の即 100% は canary の意味がない。verify 無しの canary も同様。
  4. auto-rollback Automation を導入:verify 失敗で自動 rollback、prod ダメージ最小化。
  5. approval は複数人 group:単一 approver の休暇で release 凍結を防止。
  6. executionConfigs.serviceAccount を user-managed に:default SA は権限が広い。最小権限 SA を target ごとに作る。
  7. custom Worker Pool を使う:Private GKE / Cloud SQL Private IP がある target は CD 側も Cloud Build Private Pool が必須。
  8. predeploy で smoke test, postdeploy で baking + 通知:phase の前後に hook を入れて「自動運転」できる pipeline に。
  9. GCS snapshot バケットに lifecycle 設定:90 日以上経った release artifact は自動削除でコスト抑制。
  10. Binary Authorization と接続:CD runner SA に roles/binaryauthorization.policyEvaluator、cluster 側で BA を ENABLED、Cloud Deploy 側で requiredAttestors 検証エラーで自動 halt。

3Artifact Registry 徹底解剖

Artifact Registry (AR) は Container Registry (gcr.io) の後継で、Docker だけでなく言語パッケージ・OS パッケージ・Helm chart を一元管理する universal artifact store。試験では「Standard / Remote / Virtual repo の違い」「Cleanup Policy / Tag Immutability」「Vulnerability Scanning と Artifact Analysis の関係」「リージョン選定の影響」「コスト計算」が頻出。

「Artifact Registry is the recommended service for managing container images and language packages.」 — Artifact Registry overview

3.1 対応フォーマット一覧

フォーマット用途クライアント例
Docker / OCIコンテナイメージdocker push asia-northeast1-docker.pkg.dev/...
MavenJava / Kotlin / Scalamvn deploy + artifactregistry-maven-wagon
npmNode.jsnpm publish + google-artifactregistry-auth
PythonPyPI 互換twine upload / pip install
Helm (OCI)Kubernetes charthelm push chart.tgz oci://...
AptDebian/Ubuntu .debapt-get install
YumRHEL/CentOS .rpmyum install
GoGo modulesGOPROXY=https://...artifactregistry.dev
Kubeflow PipelinesML pipeline packagesVertex AI Pipelines 連携
Generic任意ファイル(v2025+)gcloud artifacts generic upload

3.2 Repository モード:Standard / Remote / Virtual

モード役割典型 use caseコスト
Standard自社 push の artifact を保管(プライマリ)自社 build の Docker image / 内製ライブラリストレージ + ネットワーク
RemoteDocker Hub / Maven Central / npmjs / PyPI 等の透過キャッシュOSS 依存の取得を高速化 + ネット遮断環境からも参照可upstream cache のストレージ
Virtual複数 Standard / Remote を 1 つの endpoint に集約(優先順位付き)「内製 → OSS の順で探索」を 1 URL で実現下位 repo のストレージ
💡 典型構成 — Virtual で「内製優先 + OSS フォールバック」
Virtual Repo: prod-virtual ├─ priority 1: Standard "internal-libs" # 自社 build artifact ├─ priority 2: Remote "maven-central-cache" # Maven Central の透過 cache └─ priority 3: Remote "docker-hub-cache" # Docker Hub の透過 cache → 開発者は prod-virtual 1 URL を pom.xml に書くだけ。 → ネットワーク遮断環境からも、過去取得 OSS は cache 経由で取得可能。 → 内製ライブラリと同名 OSS があれば内製優先で「依存混同攻撃」を防げる。

3.3 Cleanup Policy / Tag Immutability / Vulnerability Scanning

Cleanup Policy は AR ストレージ肥大化を防ぐ自動削除ルール。KEEP(保持)と DELETE(削除)の 2 種をリポジトリ単位で複数定義可能。Dry-run モードで挙動を試せる。

# cleanup-policy.json — 「最新 10 tag は keep、それ以外は untagged + 30 日経過で delete」 [ { "name": "keep-recent", "action": { "type": "KEEP" }, "mostRecentVersions": { "keepCount": 10 } }, { "name": "delete-old-untagged", "action": { "type": "DELETE" }, "condition": { "tagState": "UNTAGGED", "olderThan": "2592000s" # 30d } } ] # 適用 gcloud artifacts repositories set-cleanup-policies REPO \ --location=asia-northeast1 \ --policy=cleanup-policy.json \ --no-dry-run # ← 本番適用、最初は --dry-run で挙動を確認
⚠️ Tag Immutability — 一度有効化したら戻せない gcloud artifacts repositories update --immutable-tags で有効化すると 同じ tag に別 digest を push することが禁止される。:latest:dev など mutable tag は使えなくなる。無効化は不可なので、repo を作り直す必要がある。本番 repo は最初から有効化推奨。

3.4 Vulnerability Scanning / Artifact Analysis

項目仕様
有効化Container Scanning API(無料の自動スキャン)+ Artifact Analysis(高度な on-demand スキャン)
スキャン対象Docker / OCI image(Maven/npm/Python は SBOM 抽出のみ)
スキャン頻度push 時 + 30 日ごとに continuous 再評価(新 CVE 発見時の検知)
対応 OSDebian / Ubuntu / Alpine / RHEL / CentOS / RedHat UBI / 一部 Windows base
SBOMSPDX 形式で自動生成・gcloud artifacts sbom export でダウンロード可
料金$0.26 / scanned image(initial)+ continuous 込み
Pub/Sub 連携新規 CVE 発見時に container-analysis-occurrences-v1 topic に通知

3.5 リージョン選定:multi-region vs region vs zonal

選択肢レイテンシ料金典型用途
Multi-region(us / eu / asia)region 内なら低、region 跨ぎは高最も高い ($0.20/GB)グローバル分散の base image / OSS
Region(asia-northeast1 等)同 region 内で最低$0.10/GB本番 GKE と同 region の app image(推奨)
Zonal※ AR には zonal は無し(GKE は zonal あるが)
💰 落とし穴 — リージョン跨ぎ pull コスト us-central1 の AR から asia-northeast1 の GKE へ pull すると $0.12/GB の egress 料金が発生(同一 continent でも)。GKE node の autoscale で 100 node が一斉に 1 GB image を pull → $12/イベント。必ず GKE と同じ region に AR を置く。multi-region AR は「世界中から pull する OSS base image」用と割り切る。

3.6 コスト計算の全体式

月額コスト = ストレージ料金 + ネットワーク egress 料金 + Vulnerability Scan 料金 ストレージ料金 (regional): $0.10/GB/月 × (storage GB - 0.5 GB free tier) ネットワーク egress 料金: ・同一 region(VPC 内): 無料 ・同一 continent の別 region: $0.01/GB ・continent 跨ぎ: $0.05-0.12/GB ・公開 internet egress: $0.12/GB Vulnerability Scan 料金: $0.26 / 初回スキャン image (continuous は含まれる) 例:100 GB の Docker image (asia-northeast1, 月 1TB pull, 1000 unique image scan) ストレージ: 99.5 GB × $0.10 = $9.95 egress (同 region 内): $0 scan: 1000 × $0.26 = $260 → 月 $270 (本番規模、ストレージはほぼ無視できる)

3.7 ⚠️ Artifact Registry 事故ケース集

事故 1:Cleanup Policy 未設定で AR ストレージが半年で 5TB 超
症状毎日 CI が image を push、Cleanup Policy 無し → 半年で 5 TB、ストレージ $500/月。
原因tag 付き image は infinite 保持。CI が $SHORT_SHA tag で日 50 push × 180 日 × 100 MB = 900 GB / app、10 app で 9 TB。
対処① Cleanup Policy「最新 50 tag keep + untagged は 7 日で delete」を設定 ② Cloud Deploy の不要 Release を abandon ③ gcloud artifacts docker images list --include-tags で大物特定。
事故 2:Remote repo の upstream(Docker Hub)が rate limit → ビルド全停止
症状朝 9 時にビルドが一斉に toomanyrequests: You have reached your pull rate limit で fail。
原因Remote repo は 未キャッシュの初回 pull で upstream にアクセス。Docker Hub の anonymous は 100 pull/6h。
対処① Remote repo に Docker Hub authentication を設定(Secret Manager 連携)② upstream を quay.io / GCR Mirror に変更 ③ よく使う base image は Standard repo に予め push。
事故 3:mutable tag 上書きで本番デプロイ後にロールバック不能
症状:prod tag に新 image を push、不具合発覚で旧 image に戻したいが、旧 digest を誰も覚えていない / Cloud Audit Log を見ても tag 履歴は残らない。
原因Tag Immutability 無効。mutable tag は履歴を持たない。
対処① 緊急対応として Cloud Deploy の旧 Release から rollback ② Tag Immutability を有効化(新 repo 作成 + migration) ③ tag は v1.2.3 など SemVer 固定 + 別途 :prod alias を Cloud Deploy 側で管理。
事故 4:リージョン跨ぎ pull で egress 料金が $3000/月
症状us-central1 AR、asia-northeast1 GKE、HPA で 200 pod が頻繁に scale up → 月 25 TB の cross-region egress → $3000。
原因初期構築時に「グローバル base に揃える」と us multi-region に集約してしまった。
対処① asia-northeast1 にも AR を作って image を mirror ② Cloud Deploy で region 別 image を指定 ③ multi-region AR は「pull 元が世界中の OSS」専用に。
事故 5:image が突然消えた — Cleanup Policy の condition ミス
症状1 か月前にリリースした本番 image が突然 pull 不能、deploy が落ちる。
原因Cleanup Policy tagState: ANY + olderThan: 30ddry-run せずに適用、本番 tag も含めて削除された。
対処① 削除済 image は復元不可(再 build 必要) ② Cleanup Policy は必ず --dry-run で挙動確認 ③ KEEP rule を DELETE より先に評価させる構成に。
事故 6:Virtual repo の優先順位ミスで OSS 依存混同攻撃を受けかけた
症状npm の内製ライブラリと同名のパッケージが npmjs に登場、Virtual repo の優先順位設定ミスで OSS 側を pull、機密 token が外部に流出寸前。
原因Virtual の priority で Remote(npmjs) を内製 Standard より上にしていた。
対処内製 Standard を priority 1 に固定 ② 内製パッケージ名は @company-scope/ で必ず scope 化 ③ npmjs.com にも同名を defensive registration。

4Binary Authorization 深掘り

Binary Authorization (BA) は GKE / Cloud Run / Anthos に admission control を適用し、「事前に署名された image だけがデプロイ可能」「信頼された builder で build された image だけが許可」というポリシーを cluster 側で enforce する仕組み。試験では「Policy / Attestor / Attestation / Note の関係」「Admission Whitelist と Required Attestations の優先順位」「Continuous Validation」「Breakglass / Dry-run の運用」「GKE / Cloud Run / Anthos の違い」が頻出。

「Binary Authorization is a deploy-time security control that ensures only trusted container images are deployed.」 — Binary Authorization overview

4.1 ポリシー評価の内部フロー

📝 Build / Sign Phase Cloud Build build + push image Artifact Analysis CVE scan / SBOM cosign sign / gcloud beta container binauthz attestations sign-and-create KMS 鍵で digest に署名 → Attestation Note に紐付け 🛡️ Deploy / Admission Phase Deploy Request kubectl apply / Cloud Run deploy GKE Admission Webhook / Cloud Run Hook image を BA Policy Evaluator に問い合わせ Policy Evaluator 1. Admission Whitelist マッチ? → 即 ALLOW 2. Cluster-specific rule → 適用 3. Default rule → 適用 requiredAttestors を全件検証 ALLOW pod 起動 DENY (ENFORCED) or AUDIT_LOG (DRYRUN) → Continuous Validation Attestation 参照 関係するリソース Attestor: 「誰の署名を信用するか」(KMS 公開鍵) Attestation: image digest への署名そのもの Note: Container Analysis の attestation 種別 Policy: project 単位 1 つ、default + cluster rule Continuous Validation: 起動中 pod を 24h ごと再評価 Breakglass: alpha.image-policy.k8s.io/break-glass annotation でポリシー一時 bypass。Audit Log に 必ず記録される。
図 4-1:Binary Authorization の admission control フロー。Build 時に署名 → Deploy 時に Policy Evaluator が Whitelist / Cluster rule / Default rule の順で評価 → requiredAttestors を全件検証 → ALLOW / DENY を返す。DRYRUN モードでは deny でも pod は起動するが Audit Log に記録。

4.2 Policy の構造(YAML)

defaultAdmissionRule: # 全 image に適用される base rule evaluationMode: REQUIRE_ATTESTATION # ALWAYS_ALLOW / ALWAYS_DENY / REQUIRE_ATTESTATION enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG # ENFORCED_BLOCK_AND_AUDIT_LOG / DRYRUN_AUDIT_LOG_ONLY requireAttestationsBy: - projects/PROJECT/attestors/prod-attestor clusterAdmissionRules: # cluster 単位 override "asia-northeast1.prod-cluster": evaluationMode: REQUIRE_ATTESTATION enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG requireAttestationsBy: - projects/PROJECT/attestors/prod-attestor - projects/PROJECT/attestors/security-team-attestor # 2 重署名要求 "asia-northeast1.dev-cluster": evaluationMode: ALWAYS_ALLOW # dev は自由 admissionWhitelistPatterns: # image path で素通り(policy 評価しない) - namePattern: gcr.io/google-containers/* # GKE system pod (kube-system) - namePattern: asia-northeast1-docker.pkg.dev/PROJECT/oss-mirror/* globalPolicyEvaluationMode: ENABLE # GKE system image の評価も有効化(Google が提供する deny list 自動適用)
🔑 評価モードと施行モードの組み合わせマトリクス
  • ALWAYS_ALLOW + ENFORCED:全て許可。Binary Authorization を実質無効化(試験では trap 選択肢)。
  • REQUIRE_ATTESTATION + DRYRUN_AUDIT_LOG_ONLY導入直後の推奨。Audit Log を見て「もしブロックしていたら何が deny されるか」を観測。
  • REQUIRE_ATTESTATION + ENFORCED_BLOCK_AND_AUDIT_LOG本番デフォルト。未署名 image は deploy 拒否 + Log。
  • ALWAYS_DENY + ENFORCED:全 deny。緊急時の「全停止」用。

4.3 Attestor / Attestation / Note の関係

┌──────────────┐ refers to ┌───────────────┐ │ Attestor │ ──────────→ │ Container │ │ prod-attestor│ │ Analysis Note │ │ publicKey: │ │ kind: ATTESTATION_AUTHORITY │ │ KMS key v1 │ └───────────────┘ └──────┬───────┘ │ verifies ↓ ┌──────────────────────────────────────┐ │ Attestation │ │ resourceUri: https://asia-...@sha256:abc │ │ payloadType: application/vnd.in-toto+json│ │ signature: base64(...) │ │ note: prod-attestation-note │ └──────────────────────────────────────┘ # 署名作成例(cosign) cosign sign --key gcpkms://projects/P/locations/L/keyRings/R/cryptoKeys/K/versions/1 \ asia-northeast1-docker.pkg.dev/P/R/app@sha256:abc... # 署名作成例(gcloud) gcloud beta container binauthz attestations sign-and-create \ --artifact-url=asia-northeast1-docker.pkg.dev/P/R/app@sha256:abc... \ --attestor=prod-attestor \ --keyversion=projects/P/locations/L/keyRings/R/cryptoKeys/K/cryptoKeyVersions/1

4.4 Admission Whitelist vs Required Attestations の優先順位

評価順判定挙動
1admissionWhitelistPatterns マッチ即 ALLOW(attestation 不要)
2clusterAdmissionRules マッチ該当 rule で評価
3defaultAdmissionRuledefault rule で評価
4評価モードで判断ALWAYS_ALLOW / DENY、または REQUIRE_ATTESTATION → 全 attestor verify
5enforcementModeENFORCED → deny で deploy block、DRYRUN → deploy 通過 + Audit Log のみ

4.5 Continuous Validation(CV)の動作

CV は 既に起動中の pod を 24h 周期で再評価し、ポリシー違反を検出する機能。重要:CV は pod を kill しない(観測のみ)。実際にブロックされるのは「新規 deploy」のタイミング。

⚠️ CV で deny 検出 → SRE が誤って pod を kill して全停止 CV の Audit Log を見て「ポリシー違反 pod がある」と慌てて手動 delete、新規 pod は admission で deny → サービス全停止。CV は警告のみで、修正は「signed な新 image を push + 再 deploy」が正攻法。

4.6 Breakglass / Dry-run の運用

# Breakglass — 緊急時にポリシーを一時 bypass する pod annotation apiVersion: v1 kind: Pod metadata: name: emergency-fix annotations: alpha.image-policy.k8s.io/break-glass: "true" spec: containers: - image: unsigned-emergency-image:hotfix-12345 # → Admission webhook はポリシー違反でも ALLOW を返す # → Cloud Audit Log に "breakglass: true" で必ず記録される # → Cloud Logging alert で「breakglass 使用」を即時通知すべき
🚨 Breakglass 多用 = ポリシー形骸化 Breakglass は「障害時の最終手段」。常用すると BA を導入している意味がない。「breakglass 使用 = 必ず post-mortem 対象」とする組織ルールを設けるべき。
また、SRE が手順書に「とりあえず breakglass 付ければデプロイできる」と書いてしまう anti-pattern が頻発するので、Cloud Logging で resource.type="k8s_pod" AND jsonPayload.annotations.alpha.image-policy.k8s.io/break-glass="true" を監視 + 自動 Slack 通知。

4.7 GKE / Cloud Run / Anthos での違い

項目GKECloud RunAnthos / GKE Enterprise
有効化--binauthz-evaluation-modeservice の --binary-authorizationcluster registration 時
クラスタ rule対応非対応(default rule のみ)対応
Continuous Validation対応非対応対応
Breakglasspod annotation--breakglass deploy flagpod annotation
system image whitelist自動(globalPolicyEvaluationMode)不要(Google managed)自動
Audit LogCloud Audit LogsCloud Audit LogsConnect Gateway 経由でも記録

4.8 ⚠️ Binary Authorization 事故ケース集

事故 1:breakglass を運用手順書化、本番デプロイの 60% で常用 → BA 形骸化
症状BA 導入 1 年後、署名フローを CI で組まずに「困ったら breakglass」が定着、Audit でポリシー違反多発を指摘。
原因署名フロー(Cloud Build → KMS sign → Attestation)が CI に組み込まれていない / signing key の権限管理が複雑で開発者が嫌った。
対処① Cloud Build template で「build → cosign sign → attestation create」を 1 step 化 ② breakglass 使用は P0 incident 扱い ③ Cloud Logging alert で即通知。
事故 2:CV で deny 検出 → 慌てて pod delete、再起動で admission に弾かれ全停止
症状CV ログで「ポリシー違反 pod 50 個」を見て SRE が kubectl delete pod、Deployment が再起動を試みるも admission deny で pod 0、ユーザーリクエスト 503。
原因CV は警告のみ・kill はしない。実 deploy では未署名 image が deny される。
対処① 該当 image を急遽 sign + attestation 作成 ② または breakglass 付き Deployment で一時復旧 ③ CV ログは「pod kill のトリガー」にせず「次 release で修正必須」のシグナルに留める運用に。
事故 3:DRYRUN のまま「もう本番だろう」と忘れて 6 か月放置
症状BA 導入したのに未署名 image が普通に prod に入っていた、Audit Log を見たら DRYRUN モード。
原因導入時 DRYRUN → 検証完了後に ENFORCED 切替を実施し忘れ。
対処enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG に変更 ② IaC(Terraform / gcloud script)で policy 管理 ③ 「DRYRUN は最大 30 日」のチェックリスト化。
事故 4:admissionWhitelistPatterns が緩すぎて任意 image が通過
症状namePattern: gcr.io/* と書いてしまい、Google Container Registry の任意 image(攻撃者が用意した repo 含む)が deploy 可能だった。
原因ワイルドカードが広すぎる。本来は gcr.io/google-containers/*gcr.io/PROJECT_ID/* 限定にすべき。
対処① pattern を狭める ② IaC で policy をレビューフロー必須に ③ Audit Log で「whitelist で通過した image」を週次レビュー。
事故 5:Attestor の KMS 鍵が削除されて全署名が無効化、prod デプロイ全停止
症状不要そうな KMS key を削除 → 翌日のデプロイで全 image が「verify failed」で deny。
原因Attestor が参照する KMS key version を削除すると公開鍵で署名検証できなくなる。KMS key 削除は 24h 待機後に物理削除される(猶予あり)が UI 上は即時 disabled。
対処① 24h 以内なら gcloud kms keys versions restore で復旧可 ② KMS key には 削除防止 IAM Deny policy を設定 ③ key rotation 時は旧 version も Attestor から参照させて grace period。
事故 6:複数 attestor を要求した結果、CI が並列署名できず deploy 時間 30 分増
症状build → security-scan-sign → manual-approval-sign の 3 attestor 直列で deploy が遅い。
原因各 attestation 作成を直列 step で実装、CI の並列性を使えていなかった。
対処① Cloud Build の waitFor: ['-'] で並列実行 ② 自動化可能な signing は CI で並列、人手 approval だけ最後に直列。

5SLSA Framework 徹底理解

SLSA (Supply-chain Levels for Software Artifacts、サルサと読む) は OpenSSF が策定するサプライチェーンセキュリティの段階的成熟度フレームワーク。SLSA v1.0 は Build Track (Build L1-L3) を中心に標準化されています。試験では「各レベルの達成要件」「Provenance の構造」「Cloud Build / Software Delivery Shield での自動達成」「in-toto attestation との関係」が頻出。

「SLSA is a security framework, a checklist of standards and controls to prevent tampering, improve integrity, and secure packages and infrastructure.」 — SLSA v1.0 spec

5.1 SLSA Build Levels (v1.0)

SLSA v1.0 Build Track L1 Provenance exists L2 Hosted + Signed L3 Hardened + Isolated L4 (将来予定) 「来歴情報が存在」 Provenance 生成のみ 改ざん検知不可 手書き OK 「ホスト型 build + 署名」 Build platform でホスト Provenance に署名 改ざん検知可 「Hardened + 隔離」 Build run 間が完全隔離 署名鍵が user inacc. Provenance 偽造 ほぼ不可 (v1.0 では未定義) v1.1+ で Hermetic / Reproducible build を予定 🏗️ Google Cloud での到達例 L1:手動 build + cloudbuild.yaml をログに残す L2:Cloud Build (default Pool) — automated build + provenance 自動生成 L3:Cloud Build with options.requestedVerifyOption: VERIFIED — VM isolation + 署名鍵が GCP 管理(user inaccessible)
図 5-1:SLSA v1.0 Build Levels と Google Cloud での到達手段。Cloud Build は VERIFIED option を有効化するだけで SLSA Build L3 相当の provenanceを自動生成する。

5.2 各レベルの達成要件詳細(公式 spec ベース)

要件L1L2L3
Provenance 存在必須(手書き可)必須必須
Build platform でホスト必須必須
Provenance 自動生成必須必須
Provenance に署名必須必須
Provenance authenticated(検証可能)必須必須
Build run 間の Isolation必須(VM/コンテナ単位の隔離)
署名鍵が user-inaccessible必須(KMS で user は access 不可)
Build platform の hardening必須(admin が偽造不可)
Hermetic build推奨(必須ではない)
Reproducible build推奨

5.3 Provenance の構造(in-toto attestation)

Provenance は in-toto attestation 仕様に則った JSON。subject(成果物)、predicateType(種別)、predicate(来歴情報本体)から成る。

{ "_type": "https://in-toto.io/Statement/v1", "subject": [{ "name": "asia-northeast1-docker.pkg.dev/my-prj/repo/app", "digest": { "sha256": "abc123..." } }], "predicateType": "https://slsa.dev/provenance/v1", "predicate": { "buildDefinition": { "buildType": "https://cloudbuild.googleapis.com/CloudBuildYaml@v1", "externalParameters": { "source": { "repository": "https://github.com/myorg/myapp", "ref": "refs/heads/main", "digest": { "sha1": "def456..." } } }, "internalParameters": { "trigger": "projects/PRJ/triggers/main-build", "substitutions": { "_ENV": "prod" } }, "resolvedDependencies": [ { "uri": "gcr.io/cloud-builders/docker", "digest": { "sha256": "..." } } ] }, "runDetails": { "builder": { "id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v1", "version": { "cloudbuild": "1.0.0" } }, "metadata": { "invocationId": "abc-def-123", "startedOn": "2026-05-29T10:00:00Z", "finishedOn": "2026-05-29T10:05:00Z" }, "byproducts": [{ "uri": "gs://logs/build-abc-def-123" }] } } }

5.4 Software Delivery Shield の全機能マップ

Software Delivery Shield (SDS) は 「Source → Build → Deploy」全フェーズを束ねる Google Cloud のサプライチェーンセキュリティ傘ブランド。個別の機能を組み合わせて使う。

Software Delivery Shield(傘ブランド) ① Source 保護 • Cloud Workstations(managed IDE) • Cloud Source Repositories • GitHub / GitLab statements • Assured OSS (Java / Python) → 検証済 OSS 依存 mirror • On Demand Scanning • VPC SC で開発環境隔離 ② Build / Verify 保護 • Cloud Build (SLSA L3) • Artifact Registry • Artifact Analysis (CVE/SBOM) • cosign signing • in-toto attestation • Binary Authorization attestor / policy ③ Deploy / Runtime 保護 • Cloud Deploy • Binary Authorization enforcement • Continuous Validation • GKE Posture / Security Posture • Container Threat Detection (SCC) • Cloud Audit Logs • Cloud KMS / EKM
図 5-2:Software Delivery Shield の機能マップ。Source / Build / Deploy の 3 フェーズで個別機能を組み合わせ、エンドツーエンドのサプライチェーン保護を実現。

5.5 cosign による署名フロー(KMS バックエンド)

# 1) KMS 鍵を作成(asymmetric sign 用) gcloud kms keyrings create my-signing-ring --location=asia-northeast1 gcloud kms keys create app-signer \ --keyring=my-signing-ring --location=asia-northeast1 \ --purpose=asymmetric-signing --default-algorithm=ec-sign-p256-sha256 # 2) Cloud Build から cosign で署名(OIDC を使うか KMS を直接) - name: 'gcr.io/projectsigstore/cosign:v2.2.4' env: ['COSIGN_EXPERIMENTAL=1'] args: - 'sign' - '--key=gcpkms://projects/$PROJECT_ID/locations/asia-northeast1/keyRings/my-signing-ring/cryptoKeys/app-signer/versions/1' - 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/repo/app@${_DIGEST}' # 3) Binary Authorization 用 attestation も同時に作成 - name: 'gcr.io/cloud-builders/gcloud' args: - 'beta' - 'container' - 'binauthz' - 'attestations' - 'sign-and-create' - '--artifact-url=asia-northeast1-docker.pkg.dev/$PROJECT_ID/repo/app@${_DIGEST}' - '--attestor=prod-attestor' - '--attestor-project=$PROJECT_ID' - '--keyversion=projects/$PROJECT_ID/locations/asia-northeast1/keyRings/my-signing-ring/cryptoKeys/app-signer/cryptoKeyVersions/1' # 4) 検証 cosign verify --key gcpkms://projects/.../app-signer/versions/1 \ asia-northeast1-docker.pkg.dev/$PROJECT_ID/repo/app@${_DIGEST}

5.6 ⚠️ SLSA 実装の事故ケース

事故 1:Provenance を生成しているが署名検証していない、改ざんに気付けない
症状Cloud Build で provenance 出力済、しかし downstream(Cloud Deploy / GKE)で signature 検証を有効化していない。攻撃者が改ざんした provenance を渡しても検出されない。
原因SLSA L2/L3 達成と「実際に検証する」は別タスク。検証フローを実装していないと L1 と等価。
対処① Cloud Deploy の predeploy hook で cosign verify-attestation 実行 ② Binary Authorization の required attestor に provenance attestor を含める ③ CI で slsa-verifier 実行。
事故 2:hermetic build を主張していたが、Dockerfile に RUN apt-get install が残存
症状「うちは hermetic build」と謳っていたが Debian repository の version 変動で再現性が崩れていた。
原因Hermetic は「ビルド時にネットワーク依存ゼロ」を要求。apt-get installpip install(version 固定なし)は違反。
対処① 依存は事前にロックファイル(requirements.txt + hash、package-lock.json)で固定 ② base image は digest pin ③ Bazel など hermetic build 専用ツールに移行検討。
事故 3:cosign の signing key を GitHub Secrets に保存 → リポジトリ流出
症状private key を GH Actions secret に格納、開発者の権限管理ミスで流出、任意の image が「正規」として署名された。
原因L3 要件「署名鍵が user-inaccessible」を満たしていない(GH に持ち出している時点で違反)。
対処① KMS に移行(鍵 export 不可) ② GH Actions からは Workload Identity Federation で KMS sign API を叩く ③ 流出した鍵で署名された image は全て invalid 化 + 再 build。
事故 4:自前 builder(self-hosted runner)で provenance を作成 → 信頼の連鎖が断たれる
症状自社 EC2 上の Jenkins で provenance を生成、Cloud Build に切り替えるまで L2 すら満たせていなかった。
原因L2/L3 は「Build platform でホスト」が必須。自前 runner は user が tamper できる前提なので Provenance の信頼性が低い。
対処① Cloud Build / GitHub Actions(managed)/ GitLab.com hosted runner に移行 ② どうしても self-hosted runner を使うなら、独立した「attestor」サービスを別 platform で構築。

6Secret & Key 管理深掘り

本章では Secret Manager / Cloud KMS / HSM / EKM / Workload Identity Federation (WIF) / Parameter Manager を整理。試験では 「SA キーは禁止 → WIF」「KMS と HSM と EKM の使い分け」「Secret rotation の自動化」が頻出。

6.1 Secret Manager — rotation の仕組み

項目仕様
1 secret の version 上限10,000
各 secret payload 最大サイズ64 KiB
レプリケーションautomatic(multi-region)または user-managed(指定 region)
暗号化Google-managed key(既定)または CMEK
Rotationbuilt-in は通知のみ(Pub/Sub に「rotation 期限が来た」を送る)。新 version の生成はCloud Functions / Workflows で自前実装
Aliasesversion に latestprod エイリアスを付与可能
料金Active secret version $0.06 / 月、access 1 万回 / $0.03
# Rotation 通知の設定(topic は事前に作成) gcloud secrets update my-secret \ --topics=projects/PRJ/topics/secret-rotate \ --next-rotation-time=2026-08-01T00:00:00Z \ --rotation-period=2592000s # 30 日ごと # Pub/Sub から起動される Cloud Function 例(pseudo) def rotate(event, context): new_value = generate_new_db_password() secretmanager.add_secret_version("my-secret", new_value) update_database_user_password(new_value) # 旧 version は disable せず参照を残す(rollback 用に 1-2 世代 grace period)

6.2 Cloud KMS / HSM / EKM の使い分け

サービス鍵の場所FIPS料金(symmetric)典型用途
Cloud KMS (software)Google data center(software)FIPS 140-2 L1$0.06 / 鍵 / 月大半の暗号化、CMEK
Cloud HSMGoogle data center 内 HSM ハードFIPS 140-2 L3$1.00 / 鍵 / 月 + 操作課金金融 / 政府 / 高セキュリティ規制
Cloud EKM顧客のオンプレ HSM / 外部 KMS顧客次第(多くは L3)EKM 自体は $0、外部 KMS の料金 + API call「鍵が Google 側に絶対に渡らないこと」が法的要件
🔑 試験での即答ポイント
  • 「鍵が GCP 外部に置かれる必要がある」→ EKM(Fortanix / Thales / Ionic / Equinix SmartKey 等と連携)
  • 「FIPS 140-2 Level 3 を要求」→ HSM(または EKM のバックエンドが L3)
  • 「コスト最小で CMEK」→ KMS (software)
  • 「Cloud Run / GKE / BigQuery / Cloud SQL の CMEK」→ KMS で十分(HSM は必要なら)

6.3 Workload Identity Federation (WIF) — キーレス認証

External IdP GitHub Actions OIDC GitLab CI / AWS / Azure on-prem OIDC JWT Workload Identity Pool + Provider (OIDC/SAML/AWS) attributeMapping attributeCondition JWT 内 claim を検証 STS Security Token Service JWT を検証 → Federated Token 発行 → SA Impersonation (generateAccessToken) 短期 OAuth token GCP API GCS / BigQuery / Cloud Run / Secret Manager... SA 権限で実行 ⚠️ SA キー (.json) は一切作成・配布しない(漏洩リスクゼロ) token は最大 1 時間で expire、外部 IdP の OIDC を rotate するだけで全 workload 自動更新
図 6-1:Workload Identity Federation のフロー。外部 IdP (GitHub/GitLab/AWS/Azure/on-prem OIDC) の JWT を WIF Pool の Provider で検証 → STS が短期 OAuth token を発行 → SA を impersonation して GCP API を呼ぶ。SA キー .json ファイルが不要

6.4 GitHub Actions から WIF 設定例

# 1) WIF Pool と Provider を作成(GCP 側) gcloud iam workload-identity-pools create gh-pool --location=global gcloud iam workload-identity-pools providers create-oidc gh-provider \ --workload-identity-pool=gh-pool --location=global \ --issuer-uri="https://token.actions.githubusercontent.com" \ --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \ --attribute-condition="assertion.repository=='myorg/myapp'" # repo 単位制限 # 2) SA に WIF principal を紐付ける gcloud iam service-accounts add-iam-policy-binding ci-runner@PRJ.iam.gserviceaccount.com \ --role=roles/iam.workloadIdentityUser \ --member="principalSet://iam.googleapis.com/projects/NUM/locations/global/workloadIdentityPools/gh-pool/attribute.repository/myorg/myapp" # 3) GitHub Actions workflow(鍵不要) permissions: id-token: write # ← OIDC token を発行 contents: read jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: google-github-actions/auth@v2 with: workload_identity_provider: projects/NUM/locations/global/workloadIdentityPools/gh-pool/providers/gh-provider service_account: ci-runner@PRJ.iam.gserviceaccount.com - run: gcloud builds submit ...

6.5 Parameter Manager(2025 GA)

Parameter Manager は 「機密でない構成値」を Secret Manager と同じ思想で管理するサービス(feature flag、URL、tuning param 等)。Secret Manager よりサイズ上限が大きい (1 MB)、format(JSON/YAML/UNFORMATTED)対応、global vs regional 選択可、料金がより安価。Secret は SM、設定値は PM と使い分け推奨。

7デプロイ戦略の完全比較

「どの戦略をいつ選ぶか」は試験頻出かつ実務頻出の判断ポイント。新旧 version の共存可否・トラフィック制御の粒度・rollback の速さ・コスト・複雑性の 5 軸で比較します。

7.1 戦略選定マトリクス

戦略新旧共存段階公開rollback 速度追加リソース複雑性典型 use case
Recreate不可(瞬間ゼロ)×遅(再 deploy)1xstate を持つ単一インスタンス、メンテ窓あり
Rolling Update一時的に混在△(pod 単位)1-1.25xK8s デフォ、後方互換あるなら万能
Blue-Green完全共存×(瞬時切替)速(router 切戻し)2x大規模 release、ロールバック即時性重視
Canary完全共存○(%)1-1.2x中-高新機能のリスク検証、SaaS 標準
Traffic Splitting / A-B Test完全共存○(細粒度)1.x-2xUX 計測、ML モデル比較
Shadow / Mirror完全共存○(ユーザー影響ゼロ)2x新バックエンドの本番負荷テスト
Feature Flag同 binary 内で切替○(ユーザー単位)瞬時1x中(flag 管理ツール必要)機能単位の独立 release、リスク隔離
💡 試験での選定ヒント
  • 「即座にロールバックできる必要がある」→ Blue-Green or Canary(Rolling は遅い)
  • 「ユーザーの 1% に新機能を試したい」→ Canary or Feature Flag
  • 「新 DB schema との互換性を本番 traffic で検証したい」→ Shadow / Mirror
  • 「コスト最小」→ Rolling Update
  • 「メンテ窓 OK の社内システム」→ Recreate

7.2 各戦略の Google Cloud 実装

戦略GKECloud RunApp Engine
RollingDeployment RollingUpdate新 revision の段階 traffic 移行—(自動 rolling)
Blue-GreenService の selector 切替 / Gateway HTTPRoutetraffic 0→100% 瞬時切替migrate-traffic(瞬時)
CanaryCloud Deploy canary strategy / Gateway HTTPRoute weighttraffic split (10/90→50/50→100/0)traffic split(min 1%)
Traffic SplittingGateway HTTPRoute weightmulti-revision traffic split標準対応(IP / Cookie / Random)
ShadowIstio mirroring / Gateway HTTPRoute mirror非標準(自前で行う)

7.3 ML パイプライン特有のデプロイ戦略(Vertex AI Pipelines / Endpoints)

戦略説明Vertex AI 実装
Champion / Challenger現行 model (champion) と新 model (challenger) を traffic split で並走Endpoint の traffic_split (90/10)
Shadow (model)新 model に request mirror、予測結果のみ比較Vertex AI Endpoints の shadow model
Multi-armed Banditパフォーマンスが良い model に動的に traffic を寄せるVertex AI Vizier + custom routing
Auto-rollback (drift detection)Model Monitoring で feature drift / prediction drift 検出 → 旧 model に自動戻しVertex AI Model Monitoring + Cloud Function

8事故ケース総集編 / トラブルシュート

8.1 全章の事故ケース一覧

#領域事故根本原因即対処
1Cloud BuildDefault Pool で Private GKE に届かず hangPool 選択ミスPrivate Pool + VPC peering
2Cloud BuildSecret 値がログに平文出力echo / set -xsecret rotation + ログ削除
3Cloud Buildsubstitution typo が prod に流出ALLOW_LOOSEMUST_MATCH 固定
4Cloud Build.gcloudignore 無しで毎回 800 MB uploadテンプレ未設定.gcloudignore + Kaniko
5Cloud BuildPrivate Pool quota 枯渇で全社凍結quota 計画なしquota 増 + alert
6Cloud BuildwaitFor ミスで test 前に image pushallowFailure 誤用tag immutable + cleanup
7Cloud Buildlegacy default SA で権限昇格穴SA 移行未対応user-managed SA 強制
8Cloud BuildqueueTtl 1h で深夜 jobs 全 expirequota 不足queueTtl 延長 + quota 増
9Cloud Deploy承認待ちで 2 週間凍結approval timeout なしgroup approver + automation
10Cloud Deploycanary verify 失敗で自動 rollback されずauto-rollback 未設定Automation rule 設定
11Cloud Deployimage tag 混乱で再現性疑念:latest 使用tag immutable + digest pin
12Cloud Deploymulti-target 一部失敗で version skewretry 設計なし全 region rollback automation
13Cloud DeployCD runner SA 権限不足で deploy 403RBAC / IAM 不足roles/clouddeploy.runner 付与
14Cloud DeployRelease delete で Rollout 履歴消失delete vs abandon 混同abandon + Audit Log export
15Cloud DeploydeployParameters typo で prod が dev DB を参照階層マージ理解不足Target で必ず override
16ARCleanup Policy 無しで 5 TBテンプレ未設定policy + dry-run
17ARDocker Hub rate limit で全 build failupstream 認証なしRemote repo に auth 設定
18ARmutable tag 上書きで rollback 不能:prod tag 使用Tag Immutability + SemVer
19ARリージョン跨ぎ pull で $3000/月region 選定ミスGKE と同 region に AR
20ARCleanup Policy で本番 image 消失dry-run 怠った--dry-run 必須化
21ARVirtual repo の優先順位ミスで依存混同攻撃OSS 先評価内製 Standard を priority 1
22BinAuthbreakglass 常用でポリシー形骸化signing CI 未整備signing 自動化 + P0 incident 化
23BinAuthCV deny で pod delete → 全停止CV 仕様誤解CV は警告のみ、kill 禁止
24BinAuthDRYRUN 放置で 6 か月未署名通過運用切替忘れIaC 管理 + 30 日チェック
25BinAuthwhitelist 緩すぎで任意 image 通過pattern が広いrepo 限定 + 週次レビュー
26BinAuthKMS key 削除で全署名無効IAM Deny なしkey restore + Deny policy
27BinAuthmulti-attestor 直列で deploy 30 分増並列化不足waitFor で並列
28SLSAprovenance 生成のみで検証なしdownstream 未実装cosign verify を CD に
29SLSAhermetic build 主張するも apt-get install仕様理解不足lockfile + base digest pin
30SLSAsigning key を GH Secrets に保存 → 流出L3 要件違反KMS 移行 + WIF
31SLSAself-hosted runner で provenanceL2 未達成managed builder へ移行

8.2 試験で頻出のパターン

🔑 即答マトリクス(試験本番で迷ったらこれ)
問題のキーワード正解(即答)
Private GKE / Cloud SQL Private IP / VPC SC + Cloud BuildPrivate Pool
GitHub Actions / 外部 CI から GCP に SA キー無しで認証Workload Identity Federation
未署名 image の本番デプロイを cluster 側で阻止Binary Authorization(REQUIRE_ATTESTATION + ENFORCED)
同じ tag に push しても prod デプロイされる image が変わらない仕組みCloud Deploy が image を digest で pin
段階的に traffic を流して問題があれば自動 rollbackCloud Deploy canary + verify + Automation
Provenance を自動生成して改ざん不可Cloud Build with VERIFIED option(SLSA L3)
FIPS 140-2 L3 + GCP 内Cloud HSM
鍵が GCP 外部に絶対に出ないCloud EKM
artifact のストレージを自動で削減Artifact Registry Cleanup Policy
OSS 依存を社内に透過 cacheArtifact Registry Remote Repository
内製 + OSS を 1 つの endpoint に集約Artifact Registry Virtual Repository
Cloud Deploy の rollback 単位Rollout(Release ではない)
Canary phase の percentage の制約整数のみ、最大 5 phase
Secret Manager の rotation 実装built-in は通知のみ。Pub/Sub → Cloud Function で自前
SDS の全機能の傘Software Delivery Shield
ML model の段階 releaseVertex AI Endpoints の traffic_split / shadow model
build 中 Secret Manager を参照availableSecrets + secretEnv($$VAR で参照)

8.3 トラブルシュート意思決定フロー

💡 「ビルド/デプロイが失敗した」時の切り分け順序
  1. Cloud Audit Logs を見る:「誰がいつ何を呼んだか」を確定。Cloud Build / Cloud Deploy / Binary Authorization は全て Audit Logs に記録される。
  2. エラーメッセージで層を特定permission denied→IAM、i/o timeout→ネットワーク (Pool)、deny by binary authorization→署名、queueTtl exceeded→quota。
  3. Cloud Build log を確認:失敗 step / 直前 step を特定、substitution / secretEnv の解決ミスをチェック。
  4. Cloud Deploy Rollout の Job logs を確認:render / deploy / verify / postdeploy のどの Job で失敗したか。
  5. Binary Authorization の Audit Log を確認protoPayload.serviceName=binaryauthorization.googleapis.com でフィルタ、deny 理由を確定。
  6. quota / limit を確認gcloud compute project-info describe --project=PRJ、Cloud Monitoring の quota dashboard。
  7. 最近の変更を確認:直近 24h の cloudbuild.yaml / delivery-pipeline.yaml / IAM / VPC firewall の diff。

9Cloud Build 運用深掘り:事故・コスト・肥大化対策

Section 1 では Cloud Build の 内部動作・schema・pool・SLSA を扱いました。ここでは「実際の現場で何が燃えたか」「請求書がなぜ 3 倍になったか」「どう抑え込んだか」に絞り、より実務寄りで深掘りします。試験では設問の見た目が違っても根本原因は同じ、というパターンが多く、本章は「症状→原因→処置→教訓→観測」の 5 点セットで設計しています。

「Builds in the default pool run in a project-specific tenant, and have no access to resources in private VPC networks. Use private pools to access resources in a VPC, including Cloud SQL with private IPs, GKE clusters with private nodes, and on-premises servers.」 — Cloud Build Private Pools overview

9.1 重大事故ケース 10 件(実務深掘り版)

各ケースは 症状 / 原因 / 処置 / 教訓 / 検知 metric の 5 行で構成。Section 1 / 8 と重複しないように、より深い構成ミス・人為ミス・観測不足を中心に選定しています。

⚠️ 9.1.1 Default Pool で本番 GKE が deploy 不可、Private Pool へ緊急切替
症状本番 release の kubectl apply ステップが 5 分 hang した後 i/o timeout: dial tcp 10.10.0.5:443。dev / staging では成功。
原因本番 GKE のみ Private Endpoint へ移行済みで、Default Pool(テナント VPC)からは control plane に到達不能。masterAuthorizedNetworks にも tenant range は無い。
処置gcloud builds worker-pools create で同 region に Private Pool 作成 → ② Service Networking (peering) で worker-pool 用 producer VPC を顧客 VPC に peering → ③ trigger 側で options.pool: projects/PRJ/locations/REGION/workerPools/prod-pool を指定。
教訓本番 = Private Pool、dev = Default OK」を IaC のテンプレで強制。pool 名は {env}-pool 規約。Private endpoint 化と Pool 切替は同一 PR で行う
検知Cloud Monitoring の cloudbuild.googleapis.com/build/durationoptions.pool!="projects/PRJ/locations/.../workerPools/prod-pool" かつ tag=~"prod-.*" を Alert。
⚠️ 9.1.2 substitutions typo で本番 image tag が文字列リテラル $BRANCH_NAME のまま push
症状AR に app:$BRANCH_NAME という奇妙な tag の image が並ぶ。Cloud Deploy の render は通るが、新 image を区別できず rollback できない。
原因cloudbuild.yaml 内で image: gcr.io/$PRJ/app:${_BRANCH_NAME} と書くべきところを $BRANCH_NAME と書いた。built-in は $BRANCH_NAME(trigger 時のみ展開)。API 直叩き/scheduled build では未定義のためリテラルのまま展開
処置options.substitution_option: MUST_MATCH を全 yaml に強制 → ② options.dynamic_substitutions: true${BRANCH_NAME:-unknown} のような bash 展開を有効化 → ③ AR cleanup policy で tag-state: tagged AND tag-prefixes: ["$"] を即時削除。
教訓built-in substitution($BRANCH_NAME, $TAG_NAME 等)はtrigger 経由でのみ展開される。manual / API は未定義。user substitution(_PREFIX)に統一、MUST_MATCH を CI で強制。
検知AR の image tag に $ / { / } を含む image を Cloud Asset Inventory + Cloud Function で日次検知。
💰 9.1.3 全 job で machineType e2-highcpu-32 を選択 → 月コスト 3 倍
症状請求書の Cloud Build 行が前月比 +¥430,000。ビルド回数は変わらず、time per build も短くなっているのに、なぜか月額だけ上昇。
原因「速い方が良いだろう」と全 trigger に options.machineType: E2_HIGHCPU_32 を一律設定。lint / docs build / unit test 等の 30 秒で終わる軽量 job まで 32 vCPU を起動。e2-medium($0.003/min)→ e2-highcpu-32($0.064/min)で単価 21 倍。1 min jobs × 月 5000 回でも約 ¥48,000 → ¥1,000,000。
処置① job 種別ごとに trigger を分割し machineType を再割り当て:lint=e2-medium、test=e2-standard-2、compile=n2-highcpu-8、e2e=n1-highmem-4 → ② Cloud Build Insightsp50_duration × machineType_price を可視化、最適 size を 1 か月毎にレビュー。
教訓「速い = 安い」は CI/CD では成立しない。billing = vCPU-min ベースなので、CPU が遊んでいる job は medium で十分。1 job = 1 machineTypeを原則化。
検知Cloud Billing Budget で「Cloud Build」だけのサブ予算を作り、月予算の 80% で alert。Insights の CPU 使用率 < 30% 件数を週次レポート。
⚠️ 9.1.4 並列 quota 上限で nightly job 全滅
症状毎日 2:00 AM に走る 80 件の nightly e2e suite のうち、毎晩 30 件以上が QUEUE_TTL_EXCEEDED で fail。Slack で「nightly 赤」が 1 週間続く。
原因Default Pool は1 region あたり concurrent build 30(quota)。80 件が一斉発火 → queue にあふれ、デフォルト queueTtl: 3600s(1h)を超えた job から expire。
処置Private Pool(concurrent quota: 100)に nightly を分離 → ② queueTtl: 7200sに延長 → ③ Cloud Scheduler で 10 分間隔の jitter を入れ、瞬間ピークを平準化。
教訓Default Pool の concurrent quota(30)はregion 共通の hard limit。大量並列は Private Pool 必須。queueTtl と concurrent 数は対で設計
検知Monitoring の cloudbuild.googleapis.com/internal/queue_depth(あれば custom metric)と build/status="QUEUE_TTL_EXCEEDED" count を毎時 alert。
⚠️ 9.1.5 secretEnv の漏れで Slack token が公開 build log に出現
症状外部協力会社からの脆弱性報告:GitHub mirror の build log(public)に xoxb-... の Slack Bot Token が平文出力。
原因新メンバーが env: ['SLACK_TOKEN=xoxb-...']環境変数に直書きavailableSecrets / secretEnv ルートを使わず、また set -x 有効な shell で全変数が echo されていた。
処置① 該当 Slack token を即時 revoke + rotation → ② Cloud Build log を Cloud Logging から force delete(_Default sink への exclusion + bucket purge) → ③ cloudbuild.yamlOPA / Conftest CI gate を追加し、env:TOKEN|SECRET|KEY|PASSWORD を含むキーがあれば拒否 → ④ Secret Manager 経由(availableSecrets + secretEnv)に統一。
教訓secret は必ず Secret Manager + secretEnvset -x / echo $VAR は禁止 lint ルール化。public mirror がある repo はbuild log を public に流さない
検知GitHub の secret scanning + Cloud Build log を Pub/Sub に export し、DLP で正規表現スキャン(xox[bp]-[0-9A-Za-z-]+ 等)。
⚠️ 9.1.6 Build Triggers の event filter ミスで PR 全件 build キュー溢れ
症状あるリポジトリで PR 1 本に対して5 件の build が同時に起動。月 build 数が 8,000 → 40,000 へ。並列 quota も枯渇。
原因trigger を 1 つに統合せず「lint」「test-unit」「test-integration」「build-image」「e2e」と 5 つ作成し、すべて同じ event filter(PR push)を設定。さらに includedFiles 指定なし。
処置① trigger を1 本に統合し、yaml 内で waitFor: ['-'] を使って並列ステップ化 → ② includedFiles: ["src/**", "Dockerfile"] + ignoredFiles: ["docs/**", "*.md"] で doc 変更だけの PR では build しない → ③ filter: "_PR_NUMBER != ''" でドラフト PR は除外。
教訓「trigger を増やす」≠「並列化」。1 yaml + waitFor 並列が安価かつ管理容易。includedFiles / ignoredFiles を必ず設定。
検知BigQuery export した build log で COUNT(*) GROUP BY repo_source.commit_sha が 1 を超えるものを週次レビュー。
⚠️ 9.1.7 マルチプロジェクト build の SA impersonation 設定漏れで全 deploy 失敗
症状Build project(shared-cicd)から App project(app-prod)の GKE に deploy する step で Error: serviceaccount "deployer@app-prod.iam" not found or insufficient permission
原因Build SA(cicd-runner@shared-cicd.iam)に対して、App project 側の deployer@app-prod.iam への roles/iam.serviceAccountTokenCreator が未付与。impersonation chain が切れている。
処置gcloud iam service-accounts add-iam-policy-binding deployer@app-prod.iam --member="serviceAccount:cicd-runner@shared-cicd.iam" --role="roles/iam.serviceAccountTokenCreator" → ② yaml の deploy step で --impersonate-service-account=deployer@app-prod.iam を明示 → ③ Terraform module 化し、新 project 作成時に自動付与。
教訓マルチプロジェクト構成では「SA Token Creator」が build SA → deploy SA に向けて必要。WIF と組み合わせる場合も同じ。Audit Logs(impersonation 用)を有効化しておくと事故時の追跡が容易。
検知Cloud Audit Logs で protoPayload.methodName="GenerateAccessToken" の error をフィルタし alert。
💰 9.1.8 Build cache 用 GCS bucket を誤って削除、ビルド時間 5 倍 + コスト爆発
症状「不要な bucket を整理」と称して gs://prj_cloudbuild 配下を bulk delete。翌日から全 build の平均時間が 4 分 → 20 分に伸び、月コスト +¥220,000。
原因① Cloud Build 標準の log + source upload bucket(gs://prj_cloudbuild)を削除 → ② 自前で運用していた Kaniko build cachegs://prj-kaniko-cache)も同時削除 → ③ docker layer cache が全 miss、依存層の再 build で 5 倍時間。
処置gsutil rb 30 日以内なら bucket 名は recreate 可。soft-delete 有効化(GCS bucket の Soft Delete 機能)で 7 日以内なら restore 可。 → ② Kaniko cache は再生成(最初の build だけ遅い) → ③ IAM Deny policystorage.buckets.delete*_cloudbuild / *-cache に対し全員拒否。
教訓Build 関連 bucket は命名規約 + Deny policy + Soft Deleteの 3 重防御。cache の有無を build time SLI で監視し、悪化したら即座に検知。
検知Monitoring の build/duration{trigger="xxx"} p50 を SLI 化し、24 h で +30% 悪化したら alert。
⚠️ 9.1.9 Docker layer cache の依存層変更検知ミスで stale base image が本番へ
症状セキュリティチームから「openssl CVE-2024-xxxx が本番に存在」と指摘。再 build しても CVE が残る。
原因DockerfileFROM python:3.11(mutable tag)+ --cache-from古い base layer を強制再利用。Cloud Build 側は「Dockerfile 行が変わらない = base layer 再利用」と判断し、新しい upstream patch を pull しない。
処置① base image はdigest pinFROM python:3.11@sha256:...)に変更 → ② 週次 cron で base image の latest digest を取得し、新しければ PR 自動作成(Renovate / Dependabot)→ ③ --no-cache ビルドを週 1 回強制実行する schedule trigger 追加。
教訓cache hit は build 高速化に有効だが、security patch を pull しなくなる副作用がある。digest pin + 定期的な cache 無効化が必須。
検知Artifact Analysis の vulnerability scan で HIGH 以上が検出されたら即時 Pub/Sub → Slack。
💰 9.1.10 timeout 10 分で長尺ビルド連続失敗 → 再ビルド rush で月コスト 3 倍
症状monorepo の big-bang build(45 分)にデフォルト timeout 10 分を超え連続 fail。dev が手動で retry → 1 commit に対し平均 5 build。月 build 時間 +200%。
原因cloudbuild.yaml 内に timeout: 600s(10 分)と書かれていたが、Bazel build が肥大化して 45 分に。timeout 後の自動 retry は無いが、人手 retry が CI で観測されず放置。
処置timeout: 3600s(1h)に拡張 → ② Bazel の Remote Build Execution + Remote Cache を導入し 45 分 → 12 分 → ③ options.disk_size_gb: 200 を指定して I/O wait 削減 → ④ retry budget を Cloud Build 外で実装(GitHub Actions matrix で max 2 回まで)。
教訓timeout はp99 build time × 1.5 を目安に。自動・手動の retry を観測しないと「失敗 → 再 build」のコスト螺旋に気づけない。
検知BigQuery export した build log で commit_sha ごとの build 回数 > 2 を週次 dashboard。

9.2 Cloud Build コスト構造の解剖

「請求書を見て驚く」を防ぐには、まず何が課金されているかを分解理解することが先決です。Cloud Build の料金は「ビルド時間(vCPU-min)× machineType 単価」を主軸に、付随する storage / network / private pool surcharge で構成されます。

9.2.1 主要コンポーネント別の課金

コンポーネント課金単位備考
Build timevCPU-min × machineType 単価主要コスト。free tier 月 120 build-min
Artifact storageGCS の通常料金($0.020/GB/月、Standard)gs://PRJ_cloudbuild の log + source upload
Image storageArtifact Registry の料金($0.10/GB/月)Cloud Build 自体ではなく AR 側で課金
Network egress(同 region 内)無料AR、GKE 等が同 region なら egress 0
Network egress(cross-region / internet)$0.01〜0.12/GBcross-region pull、外部 registry へ push 時要注意
Private Pool VM 起動時間e2-medium 相当 = $0.008/min/instance(pool 単位)build idle 中もmin_instances 分は課金
Private Pool 用 IP$0.004/h × IP 数peering / NAT 経由なら別途 NAT 課金あり
「You are billed for the time each build runs. Builds that use the e2-medium machine type are free for the first 120 minutes per day per billing account. Beyond the free tier, builds are billed at the rates listed for each machine type.」 — Cloud Build pricing

9.2.2 machineType 別の単価表(2026 年時点)

machineTypevCPUmemory単価($ / build-min)典型 use case
e2-medium(デフォルト)14 GB$0.003lint、docs build、小規模 unit test
e2-standard-228 GB$0.006中規模 test、軽量 docker build
e2-highcpu-888 GB$0.016compile 主体(CPU bound)
e2-highcpu-323232 GB$0.064monorepo の big build、parallel test
n1-highcpu-887.2 GB$0.016legacy。e2 推奨
n1-highcpu-323228.8 GB$0.064legacy。e2 推奨
⚠️ 「速い = 安い」は条件付き machineType を 32 倍速くすると単価も 21 倍。ビルド時間が単価比に応じて短縮されない場合(I/O bound、依存 download bound、シングルスレッド処理)、highcpu は単に高くなるだけ。c2 / n2 系も同じ。「CPU 使用率 70% 以上で並列性 8 以上」の job だけ highcpu を選ぶ。

9.2.3 Free tier の正確な仕様

無料枠
billing account ごとに毎日 120 build-min(e2-medium 換算)
カウント対象
e2-medium のみ。e2-highcpu-32 等を使うと free tier はそのまま消費されるが「分」単位での換算ではない
リセット
太平洋時間 0:00 にリセット(≒ JST 17:00)
累計
翌日への繰越なし

9.3 コスト肥大化の典型パターン 5 件

💰 パターン A — machineType 過剰スペック

症状:全 trigger に e2-highcpu-32 を一律設定。lint 30 秒 / build 5 分 / test 10 分のいずれも 32 vCPU で実行。

▼ コスト試算(月 5,000 build) 軽量 lint job(30s 平均): e2-medium : 5000 × 0.5min × $0.003 = $ 7.5 / 月 e2-highcpu-32 : 5000 × 0.5min × $0.064 = $ 160.0 / 月 ← 21 倍 中規模 build(5 min 平均): e2-medium : 5000 × 5min × $0.003 = $ 75.0 / 月 e2-highcpu-32 : 5000 × 5min × $0.064 = $1600.0 / 月 ← 21 倍 合計(月) e2-medium 一律 : $ 82.5 e2-highcpu-32 一律 : $ 1,760.0 ← +$1,678 / 月 ≒ ¥260,000

対処:job 種別ごとに trigger を分け、機械的に machineType を割り当てる。Cloud Build Insights でCPU 使用率 < 30% の job を四半期ごとにダウンサイズレビュー。

💰 パターン B — Docker layer cache 未活用で毎回フルビルド

症状:CI 用の Dockerfile に RUN pip install -r requirements.txt(200 deps)を毎回フルで実行。1 build 8 分のうち 6 分が pip install。

▼ Kaniko + GCS cache 導入前後 before: 8 min × 0.006/min × 3000 build/月 = $ 144 / 月 after : 1.5 min × 0.006/min × 3000 build/月 = $ 27 / 月 → -$117 / 月 # 加えて開発体験:「PR push → 8 min」→「PR push → 1.5 min」

対処Kanikogcr.io/kaniko-project/executor)+ --cache=true --cache-repo=$AR_REPO/cache を使用。docker buildx の場合は --cache-from / --cache-to で GCS / AR を指定。

💰 パターン C — Build trigger の event filter 過剰で PR 1 件 = 5 build

症状:lint / unit / int / e2e / image-build を別 trigger 化、同じ filter(PR push)に発火。PR 1 件で 5 build × 10 reviewer 押し戻し = 50 build。

対処:trigger を1 本に集約 + waitFor: ['-'] 並列 step。includedFiles で doc / md 変更を除外。draft PR / WIP PR は filter: "_PR_TITLE !~ '^WIP'" で除外。

💰 パターン D — Cross-region pull / 外部サービス egress 月 ¥1,000,000

症状:build project は asia-northeast1 だが、source の monorepo を us-central1 の GCS から download、Docker base image を Docker Hub から pull。月 30 TB の cross-region + internet egress。

▼ Egress コスト試算 cross-region pull: 30 TB × $0.02/GB = $ 614 / 月 ≒ ¥ 95,000 Docker Hub pull : 認証なし → rate limit fail → 再 build × 3 = + ¥ 200,000 想定 → 合計 +¥ 300,000 / 月

対処:① source repo と AR をbuild と同 regionに統一 → ② Docker Hub は AR Remote Repository(auth 付き)でキャッシュ → ③ options.disk_size_gb を増やして reuse。

💰 パターン E — Flaky test の自動 retry で 3 倍コスト

症状:e2e test が flaky で 30% fail。CI script で for i in 1 2 3; do pytest && break; done と書かれており、全 e2e が平均 1.8 回実行。

対処:① retry を観測可能化し、flaky test を quarantine → ② pytest --reruns 2 --reruns-delay 5 を使い失敗 test だけ retry(全 suite ではなく)→ ③ flaky 上位 10 件を週次で fix。

9.4 最適化テクニック 8 個

  1. machineType を job 種別で分離:lint = e2-medium、unit test = e2-standard-2、compile = e2-highcpu-8、e2e = n2-highmem-4。1 trigger = 1 machineType 原則。
  2. Docker layer cache の徹底:Kaniko or docker buildx --cache-to=type=registry,ref=$AR/cache,mode=max。dependencies 層を Dockerfile 上で先に COPY/RUN し、source 層を後ろに置く。
  3. Step 並列化(waitFor: ['-']:依存しない step は並列。Total time が long step に律速されるので、Cloud Build Insights の 「step duration breakdown」で律速 step を可視化。
  4. Cloud Build Pool sharing:複数 project で同じ Private Pool を共用。iam.serviceAccountUser を build SA に付与し、Pool が他 project から見える状態にする。VPC SC perimeter を同じにする必要あり。
  5. Cache to GCS(multi-build 共有):Bazel / Gradle / Maven のように外部 cache 対応 build tool は GCS bucket を remote cache に指定。Bazel なら --remote_cache=https://storage.googleapis.com/bucket
  6. timeoutSeconds の適切な設定:p99 build time × 1.5。長すぎても短すぎても損失。デフォルト 10 分は monorepo では不足。
  7. Build skip patternincludedFiles / ignoredFiles で source 変更が無い PR をスキップ。filter: "_HEAD_BRANCH != 'gh-pages'" 等で特殊 branch も除外。
  8. Cloud Build Insights による build 時間モニタ:Console > Cloud Build > History > Insights でp50 / p95 build duration / step breakdown を可視化。月次で top 10 slow step を fix。
💡 BP:cloudbuild.yaml の「最適化済みテンプレ」
options: machineType: 'E2_MEDIUM' # ← 軽量 default diskSizeGb: 100 substitution_option: 'MUST_MATCH' dynamic_substitutions: true pool: name: 'projects/${PROJECT_ID}/locations/${LOCATION}/workerPools/${_POOL}' timeout: 1800s # 30 min(p99 × 1.5) steps: # 並列 group A - id: lint name: 'gcr.io/cloud-builders/gcloud' waitFor: ['-'] # 直ちに開始 entrypoint: 'bash' args: ['-c', 'make lint'] - id: unit-test name: 'gcr.io/cloud-builders/gcloud' waitFor: ['-'] entrypoint: 'bash' args: ['-c', 'make test'] # 重い build は cache 必須 + 適切な machineType - id: build-image name: 'gcr.io/kaniko-project/executor' waitFor: ['lint', 'unit-test'] # 並列 group A 完了後 args: - '--destination=${_AR}/app:${SHORT_SHA}' - '--cache=true' - '--cache-repo=${_AR}/cache' - '--cache-ttl=72h' availableSecrets: secretManager: - versionName: 'projects/${PROJECT_ID}/secrets/slack-token/versions/latest' env: 'SLACK_TOKEN' artifacts: images: ['${_AR}/app:${SHORT_SHA}']

9.5 監視・アラート設計

9.5.1 監視すべき主要 metric

metric説明SLI / alert 例
cloudbuild.googleapis.com/build/durationbuild 全体の所要時間p95 > 20 min が 30 分続いたら warn
cloudbuild.googleapis.com/build/countbuild 回数1h 内 200 件超で abuse 検知
cloudbuild.googleapis.com/internal/queue_depthqueue 滞留数30 件超で quota 引き上げ検討
build/status="FAILURE" count失敗 build 数失敗率 > 20% で SRE alert
build/status="QUEUE_TTL_EXCEEDED" countqueue タイムアウト数1 件でも warn(quota or 並列度問題)
build/status="TIMEOUT" counttimeout 失敗数1 件でも warn(timeout 設定 or 性能劣化)

9.5.2 ビルド時間の SLI 設計例

# SLO 例:PR build の p95 < 10 min を 99% の週で達成 sli: type: requestBased goodTotalRatio: goodServiceFilter: | metric.type="cloudbuild.googleapis.com/build/duration" AND resource.labels.trigger_id="pr-trigger" AND metric.value < 600s totalServiceFilter: | metric.type="cloudbuild.googleapis.com/build/duration" AND resource.labels.trigger_id="pr-trigger" slo: rollingPeriod: 7d goal: 0.99

9.5.3 コスト・失敗率アラート

Budget alert
Cloud Billing で「Cloud Build」サービスだけのサブ予算を作成。月予算の 50%/80%/100%/120% で通知。Forecasted spend(予測) alert で月途中の異常を早期検知
失敗率 alert
Monitoring で failure_count / total_count を 1h rolling window で計算、20% 超で PagerDuty
retry abuse alert
BigQuery export した build log で commit_sha あたり > 3 builds を日次 Slack 通知
cache miss alert
Kaniko の --verbosity=info ログから CACHE_MISS 比率を抽出、80% 超でレビュー
🔑 試験ポイント(Section 9 要点)
  • Default Pool は VPC 内リソースに到達不能。Private GKE / Cloud SQL Private IP / on-prem 連携はPrivate Pool 必須
  • machineType はjob 種別ごとに分離。全 trigger に highcpu-32 は禁忌(コスト 20 倍)
  • Free tier は e2-medium 換算で日 120 build-min、繰越なし
  • secret は必ず Secret Manager + secretEnvenv 直書き禁止
  • built-in substitution($BRANCH_NAME)はtrigger 経由でしか展開されない。manual / API は未定義
  • cache は build 高速化に有効だが、base image patch を見逃す副作用。digest pin + 定期 cache flush 必須

10Cloud Deploy 運用深掘り:事故・コスト・肥大化対策

Cloud Deploy は「マネージド Skaffold」+「Promote pipeline」+「自動 verify / rollback」を一体化したサービスです。価格モデルは「targets ベース」で、頻度が低くても target 数で課金が膨らみます。本章では Section 2 / 8 にないPipeline / Render / Rollout / Automationの深部事故、コスト爆発の典型、最適化テクニックを扱います。

「Cloud Deploy is a managed service that automates delivery of your applications to a series of target environments in a defined promotion sequence.」 — Cloud Deploy overview

10.1 重大事故ケース 10 件(実務深掘り版)

⚠️ 10.1.1 Skaffold render の helm profile mismatch で値が dev のまま prod へ
症状prod target の rollout 後、kubectl get deploy -o yamlimage: app:dev-xyz + replicas: 1(dev の値)。本番が dev configuration で稼働。
原因skaffold.yaml 内で profile を profiles: [dev, prod] と並列定義していたが、Cloud Deploy Target の profiles: ["prod"] が未設定。render はactiveProfiles なしで実行され、default プロファイル(= dev 値で上書き)が適用された。
処置① 全 Target に profiles: を必須設定 → ② skaffold render --profile=prod をローカルで検証する PR テンプレ追加 → ③ Custom Target verificationkubectl diff を必ず実行し expected と比較。
教訓Skaffold profile は「Target で明示しなければ default」。テンプレ化された delivery-pipeline.yaml で profiles 欄を必須にする。
検知Cloud Deploy の Release manifests を Cloud Storage に export し、replicas != expected を日次 diff。
⚠️ 10.1.2 Canary phase 50% で verify が成功扱い → 実は全リクエストが旧 pod へ
症状canary 50% phase で verify pass、promote 完了。だが顧客から「新機能まだ見えない」報告。Pod 数は 50/50 だが、Service の selector が古い label のまま。
原因Helm chart の Service.spec.selector が固定 app=myapp,version=v1。Deployment は v2 がデプロイされたが Service は v1 だけ select。Cloud Deploy canary はPod 数で進捗判定するため、traffic が流れていなくても verify pass。
処置① canary 用にService の selector を app=myapp のみに変更(version label 削除) → ② verify script で curl -H 'X-Canary: 1' /api/version を 100 回実行し、v2 が 40-60% 返ることを検証 → ③ Gateway HTTPRoute weight 方式に移行(より明示的)。
教訓Cloud Deploy 標準の canary は「Pod 比率」を見る。traffic 比率 ≠ Pod 比率。verify は必ず実際の応答で検証する。
検知Cloud Monitoring で v1/v2 各 backend の requests_per_second を比較、期待比から ±20% 乖離で alert。
⚠️ 10.1.3 Promote 承認待ち 14 日 → 承認時には既に古い image、脆弱性付き
症状release が staging で承認待ちのまま 2 週間放置。承認後 prod に流したら、その image の OS には新規 CVE が含まれていた。
原因承認者が 1 名(休暇中)、approval timeout 未設定、release 自体は不変なのでimage rebuild されず古いまま。
処置group approver(Google Group)を必須化、roles/clouddeploy.approver を group 全員に → ② Cloud Deploy Automation で「approval pending > 72h → abandon + Slack 通知」 → ③ Binary Authorization の attestation 有効期限を 7 日に設定し、超過 image は deploy 不可。
教訓「approval が止まる」=「stale release で deploy されるリスク」。approval timeout + image expiryの組合せで強制更新。
検知Audit Log の ApproveRollout までの待機時間を BigQuery 集計、p95 > 24h で週次レポート。
⚠️ 10.1.4 multi-target promote 中に 1 region だけ fail、version skew で 12 時間放置
症状asia / us / eu の 3 region に並列 promote。eu だけ ImagePullBackOff(eu AR に image 未 replicate)。asia/us は v2、eu は v1 のまま 12 h、global LB 経由でsession sticky 違反が大量発生。
原因① AR の multi-region replication が遅延 → ② Cloud Deploy multi-target は「他 target の失敗は無視」がデフォルト → ③ alert 設定なしで人が気づかず。
処置Automation rule で「1 region でも fail なら全 region を v1 へ自動 rollback」 → ② AR は multi-region(例:asia)または同一 region への明示 push → ③ Rollout 失敗を直ちに PagerDuty。
教訓multi-target = 独立。「all or nothing」が必要なら Automation で明示的に設計。AR の cross-region replication は非同期であることを忘れない。
検知Cloud Deploy の rollout/state="FAILED" + target!="all" を即時 alert。
⚠️ 10.1.5 deployParameters の階層マージで dev DB URL が prod に漏れる
症状prod の new release が起動後、dev DB に書き込み開始。dev DB の容量逼迫で alert。本番 transactional data が dev に。
原因delivery-pipeline.yamlPipeline 階層deployParameters: { DB_URL: 'dev-db' } を設定(テスト用)。Target 階層で上書きを忘れた。Cloud Deploy は Pipeline → Stage → Target の順でマージし、後ろが勝つが、未指定なら Pipeline 値が残る。
処置① 全 Target で deployParameters を必須設定(テンプレ化)→ ② Pipeline 階層の deployParameters は削除、各 Target で個別定義 → ③ OPA gate で「Target に DB_URL 未設定なら CI fail」。
教訓deployParameters の階層マージは便利だが「未指定 = 安全な default」ではない明示派に倒すのが事故防止。
検知render 後 manifest に dev-db 文字列が含まれるかを CI で grep。
⚠️ 10.1.6 Cloud Deploy SA の権限不足で prod GKE に deploy 403
症状release が prod target に到達した瞬間、Error: permission denied: containerclusters.get で全 rollout fail。
原因execution config の serviceAccount: deploy-sa@PRJ.iam に、prod GKE 側の roles/container.developer(または相当)が未付与。dev と staging では付与済みだが prod だけ未対応。
処置gcloud projects add-iam-policy-binding APP_PRJ --member="serviceAccount:deploy-sa@PRJ.iam" --role="roles/container.developer" → ② Terraform module 化し、Target 作成時に必要 IAM を一括付与 → ③ dry-run rollout で IAM チェックを毎回事前実行。
教訓Cloud Deploy の SA は「Pipeline project の SA」が default。実 deploy 先 project ではクロス IAM 付与が必要。Module で標準化しないと環境ごとに漏れる。
検知Audit Log で permission deniedclouddeploy 起源で発生したら即 alert。
⚠️ 10.1.7 verify job が Cloud Logging に巨大ログを吐き、月 ¥800,000 課金
症状Cloud Logging の請求が前月比 +¥800,000。99% が k8s_container ログ。
原因verify job として kubectl logs を 100 pod 分、--follow で 30 分間取得。Cloud Deploy verify job の stdout はすべて Cloud Logging に保管され、$0.50 / GB の取り込み料が課金。1 日 50 release × 5 GB = 250 GB/日 = 7.5 TB/月。
処置① verify は --tail=100 + --timestamps で fixed size に → ② Logging の exclusion filter で verify job ログを除外、必要なら GCS に直接 archive → ③ verify 用 image を slim 化(busybox 等)して noisy log を抑制。
教訓verify job の stdout は全て Cloud Logging に取り込まれる取り込み課金fixed-size + sampling必須。
検知Cloud Billing で「Cloud Logging」サブ予算を作成、20% 超過で alert。
⚠️ 10.1.8 Release を delete したら過去 Rollout 履歴も消失、監査要件不適合
症状監査で「過去 90 日の deployment 履歴提示」を要求されたが、release を delete していたため Rollout が API 上消失。
原因「不要 release を整理」と gcloud deploy releases delete 実行。Cloud Deploy はcascade deleteで Rollout / Job / verify 結果まで削除。abandon(API 上隠すが履歴保持)と混同。
処置abandon を default 運用gcloud deploy releases abandon)、delete は最終手段 → ② Audit Log を BigQuery sink に export し、API 削除されても痕跡保持 → ③ IAM Deny policyclouddeploy.releases.delete を SRE 以外に拒否。
教訓「不要なら delete」は誤り。abandon = 監査保持 + 新規 promote 防止。Audit Log の export は削除前提で設計する。
検知Audit Log で DeleteRelease 自体を alert(人手 delete は要承認)。
⚠️ 10.1.9 Custom Target を社内 PaaS 用に書いたが timeout 60 min で長時間 job が全 fail
症状独自 PaaS(社内 GCE 群)への deploy を Custom Target で実装。ローリング更新が 80 分かかる構成で、毎回 timeout fail。
原因Custom Target の render / deploy job のデフォルト timeout は 60 minexecutionTimeout 未設定で fall through。
処置executionConfigs[].executionTimeout: 7200s(2h)に拡張 → ② 内部 ローリング更新を Phase 分割し、1 Phase 30 min 以内に収める → ③ Cloud Workflows で外部 long-running 処理を切り出し、Cloud Deploy 側は status polling のみ。
教訓Custom Target のexecutionTimeout はデフォルト 60 min。長尺処理は分割か外部委譲。
検知rollout/state="FAILED" + failureCause="EXECUTION_FAILED" + reason に "timeout" を含むものを alert。
💰 10.1.10 Target を環境×region×service で爆増させ月課金 ¥600,000
症状Cloud Deploy の月 invoice が ¥600,000 超。release 頻度は変わらず、target 数だけ増えていた。
原因Cloud Deploy は$0.025 / target / dayで課金。env (4) × region (5) × service (30) = 600 target。月 30 日で $450 ≒ ¥70,000 に加え、毎日のドリフトチェックが裏で動き、worker pool 課金も発生。
処置① 1 target = 「1 環境 × 1 region」に集約、1 release が複数 service を同時に進めるマルチ K8s Deployment 構成に → ② 低頻度 service(年数回 deploy)はCloud Build 直接 deployに逃がし、Cloud Deploy を外す → ③ 不要な target を四半期 review。
教訓Cloud Deploy は「target 数」が主要コストドライバ。env / region の組合せが多いほど線形に増える。「使っていない target」を残すと垂れ流し
検知Billing export を BigQuery で service="Cloud Deploy" + sku.description LIKE "%Target%" 集計、月 50% 増で alert。

10.2 Cloud Deploy コスト構造の解剖

Cloud Deploy の料金は「target 数 × 日数」が主軸で、それに worker pool(custom job 実行用)の VM 時間Cloud Build / Cloud Logging / Cloud Storage の付随コストが乗ります。

10.2.1 主要コンポーネント別の課金

コンポーネント課金単位備考
Target 利用料$0.025 / target / day使っていなくても target 存在で課金
無料枠最初の2 target / project / 月は無料小規模 project は実質無料
Render / Deploy job の Cloud Build 利用Cloud Build の vCPU-min 料金Skaffold render は内部で Cloud Build を起動
Custom Target の worker poole2-medium 相当 = $0.003 / build-minカスタム実装の job 実行時間
verify job のログCloud Logging $0.50 / GB ingeststdout が膨大だと爆発
render manifest 保管GCS Standard $0.020/GB/月release ごとに blob 保管
「You are charged $0.025 per target per day. The first two targets in your project each month are free.」 — Cloud Deploy pricing

10.2.2 target 数別コスト試算

▼ Target 数別 月額(30 日換算、free 2 引いた後) 10 target → 8 × $0.025 × 30 = $ 6.0 / 月 50 target → 48 × $0.025 × 30 = $ 36.0 / 月 100 target → 98 × $0.025 × 30 = $ 73.5 / 月 500 target → 498 × $0.025 × 30 = $ 373.5 / 月 1000 target → 998 × $0.025 × 30 = $ 748.5 / 月 ▼ 加えて release ごとに発生する: - Cloud Build: render 1 回 × deploy 1 回 × verify 1 回 = 3 build × 平均 3 min - Cloud Logging: verify stdout 100 MB/release 想定 - GCS: render manifest 1 MB/release 保管

10.3 コスト肥大化の典型パターン 5 件

💰 パターン A — Target 爆増(環境×region×service の単純積)

4 env × 5 region × 30 service = 600 target。月 ¥70,000 のベースに加え、render の Cloud Build が比例して増加。対処:「1 service 1 target」を捨て、「1 region 1 target」で複数 service を 1 release にまとめる multi-manifest 構成へ。

💰 パターン B — verify job の log 爆発(パターン 10.1.7)

Cloud Logging $0.50/GB の取り込み。verify が kubectl logs --follow を放置すると秒で TB に到達。対処:fixed size + tail + exclusion filter。

💰 パターン C — Render Cloud Build が e2-highcpu-32 で過剰

Skaffold render はテキスト処理が主。e2-medium($0.003/min)で十分。対処executionConfigs[].defaultPool.machineType: e2-medium を明示。デフォルトは e2-medium だが、誤って highcpu を継承していないか確認。

💰 パターン D — Custom Target で外部 VM 起動 → 課金二重取り

Custom Target の deploy job が GCE VM を起動して deploy 処理。Cloud Build 料金 + GCE 料金の二重課金。対処:deploy 処理を Cloud Build container 内で完結させるか、Cloud Workflows で外部処理を polling。

💰 パターン E — release を delete せず GCS が肥大

render manifest は GCS に無期限で保管。1 release 1 MB × 10000 release = 10 GB(実害は小だが、添付 file が多い場合は数 GB / release も)。対処:GCS Lifecycle Rule で 1 年以上の release object を Coldline へ移行。

10.4 最適化テクニック 8 個

  1. Target を「1 環境 × 1 region」に統合、複数 service を 1 release で進める multi-manifest 構成に。
  2. 低頻度 service は Cloud Deploy を使わない。年数回 deploy 程度なら Cloud Build から直接 kubectl apply で十分。
  3. verify job は fixed sizekubectl logs --tail=50)+ exit code で結果伝達。stdout を巨大にしない。
  4. render / deploy / verify の Cloud Build pool を共有。execution config の workerPool を統一し、Private Pool の起動コストを 1 つに。
  5. deployParameters は Target で明示。Pipeline 階層に dev 値を残さない(事故 10.1.5 対策)。
  6. Automation rule で「N 時間 promote されない → abandon」「multi-target 1 つでも fail → 全 rollback」を自動化(事故 10.1.3 / 10.1.4 対策)。
  7. delete ではなく abandon を default 運用。IAM Deny で delete を SRE 限定に。
  8. Custom Target の executionTimeout を明示。デフォルト 60 min を超える処理は分割または Cloud Workflows へ。
💡 BP:delivery-pipeline.yaml の最適化テンプレ
apiVersion: deploy.cloud.google.com/v1 kind: DeliveryPipeline metadata: name: app-pipeline serialPipeline: stages: - targetId: staging profiles: ["staging"] # ← profile 必須 strategy: standard: { verify: true } - targetId: prod-asia profiles: ["prod"] strategy: canary: runtimeConfig: kubernetes: { serviceNetworking: { service: app-svc, deployment: app } } canaryDeployment: percentages: [25, 50] # ← 整数のみ verify: true --- apiVersion: deploy.cloud.google.com/v1 kind: Target metadata: name: prod-asia gke: cluster: projects/APP_PRJ/locations/asia-northeast1/clusters/prod requireApproval: true # 承認必須 executionConfigs: - usages: [RENDER, DEPLOY, VERIFY] serviceAccount: deploy-sa@PRJ.iam.gserviceaccount.com workerPool: projects/PRJ/locations/asia-northeast1/workerPools/deploy-pool executionTimeout: 3600s # ← 明示 defaultPool: serviceAccount: deploy-sa@PRJ.iam.gserviceaccount.com deployParameters: DB_URL: "prod-db.asia" # ← Target で必ず明示 REPLICAS: "10" --- apiVersion: deploy.cloud.google.com/v1 kind: Automation metadata: name: auto-rollback selector: targets: [{ id: prod-asia }, { id: prod-us }] rules: - rolloutRestartRule: id: auto-restart-on-fail condition: { targetsPresentCondition: { missingTargets: [] } } - promoteReleaseRule: id: auto-promote-after-soak wait: 1h

10.5 監視・アラート設計

10.5.1 監視すべき主要 metric

metric説明SLI / alert 例
clouddeploy.googleapis.com/rollout/durationrollout 全体の所要時間p95 > 30 min で warn
clouddeploy.googleapis.com/rollout/countrollout 回数急増で abuse 検知
rollout/state="FAILED" count失敗 rollout 数失敗率 > 10% で SRE alert
clouddeploy.googleapis.com/release/render_durationrender 所要時間p95 > 10 min で warn(template 肥大化)
approval pending(自前計算)承認待ち期間72 h 超過で abandon 自動化
target 数Cloud Asset Inventory で list月次で diff、急増を察知

10.5.2 デプロイ frequency / lead time の SLI(DORA 4 メトリクス)

Deployment Frequency
COUNT(rollout) WHERE state='SUCCEEDED' / 日
Lead Time for Changes
rollout.created_at - commit.timestamp の p50
Change Failure Rate
COUNT(rollback) / COUNT(rollout)
MTTR
rollback.completed_at - failure.detected_at の p50
🔑 試験ポイント(Section 10 要点)
  • Cloud Deploy の主要コストドライバは「target 数 × 日数」($0.025 / target / day、最初 2 target / project は無料)
  • canary はPod 数比率で進捗判定。traffic 制御の検証は別途必要(Service selector / Gateway HTTPRoute)
  • delete ≠ abandon。履歴を残すなら abandon、delete は cascade 削除
  • deployParameters はPipeline → Stage → Target でマージ、Target で明示が安全
  • Custom Target のexecutionTimeout デフォルトは 60 min
  • multi-target は独立。all-or-nothing は Automation で明示設計
  • 承認はgroup approver + Automation timeout が事故防止セット

11Artifact Registry 運用深掘り:事故・コスト・肥大化対策

Artifact Registry(AR)はContainer / Maven / npm / Python / apt / yum / Go 等の universal artifact store。料金構造はシンプル(storage + network egress + scan)ですが、cleanup policy 未設定で青天井region 跨ぎ pull で egress 爆発vulnerability scan 課金の見落としが 3 大コスト事故源です。

「Artifact Registry charges for storage and network egress. Storage costs $0.10/GB/month after the first 0.5 GB free. Network egress is free within the same region.」 — Artifact Registry pricing

11.1 重大事故ケース 10 件(実務深掘り版)

⚠️ 11.1.1 tag を毎 build で大量付与 → metadata API が rate limit に
症状nightly e2e 中、AR への gcloud artifacts docker tags add429 Too Many Requests。同 image に対し 200 tag 付与する script を回していた。
原因AR の metadata API はproject + region で 60,000 req / minが上限。tag 追加は metadata 操作で、1 image に 10 tag × 100 image / min = 1000 req/min、複数 service で集約すると上限突破。
処置① 不要 tag を削除(:latest:branch-XXX の 100 件以上) → ② tag は意味のあるもの 3 つ以内commit_shasemverenv)に制限 → ③ digest pin 運用に移行し tag 削除も恐れない設計に。
教訓tag は「人間が指す名前」、digest は「不変な識別子」。tag 大量 = 何も指していないに等しい。運用に必要な 3 tag のみが原則。
検知AR の quota usage を Monitoring の artifactregistry.googleapis.com/quota/... で観測、80% で warn。
⚠️ 11.1.2 mutable tag :latest を本番で使用、rollback 時に image 特定不能
症状本番障害発生。「1 時間前の imageに戻したい」と SRE が requested。だが :latest しか tag されておらず、Deployment manifest にも image: app:latest。どの digest が「1 時間前」か特定不能。
原因① CI で docker push app:latest のみ。commit_sha tag なし → ② Tag Immutability 未設定 → ③ Deployment が imagePullPolicy: Always + :latest毎再起動で違う image を pull。
処置Tag Immutability を有効化--immutable-tags)→ ② CI で app:${SHA} + app:${SEMVER} を必ず付与、:latest は撤廃 → ③ Deployment はdigest pinimage: app@sha256:abc...) → ④ Cloud Deploy の rollback はRollout 単位で過去 digest に戻す。
教訓:latest本番では禁止。「最新」概念を CI と Cluster の両方に持たせると齟齬が発生。digest pin が rollback の唯一安全策
検知OPA / Conftest で manifest 内 :latest を CI で拒否。AR のリポジトリ設定で Tag Immutability を有効化済みかを Cloud Asset Inventory で監査。
💰 11.1.3 Cleanup Policy 未設定で AR storage が 5 TB、月 ¥75,000
症状請求書の Artifact Registry 行が前月比 +¥10,000。半年放置で月 ¥75,000 まで増加。
原因毎 PR push 時に image build & push、cleanup policy 未設定。1 PR で 500 MB image × 1000 PR/月 × 6 か月保持 = 3 TB。さらに base layer 重複考慮で 5 TB。
処置Cleanup Policy 作成:「tag-prefix: pr- かつ最終更新 30 日以上経過 → 削除」 → ② 必ず dry-run--dry-run)で 1 週間運用 → ③ Cloud Logging で削除イベントを監査 → ④ 本番 tag は keep-tag-revisions: 100 で最近 100 個を残す。
教訓「削除しない」は事実上 storage 青天井新 repo 作成テンプレに cleanup policy を組み込む。dry-run なしの policy 投入は事故。
検知Cloud Billing で「Artifact Registry」サブ予算、20% 超で alert。Storage size を Monitoring で取得し p99 を月次レビュー。
💰 11.1.4 cross-region pull で月 egress ¥300,000
症状GKE が asia-northeast1、AR が us-central1。毎 pod 起動で AR から image を pull、daily restart で 1 TB egress / 日 = 30 TB / 月。
原因歴史的経緯で AR を us に作成、GKE 移行時に AR を移さなかった。Cross-region egress は$0.02 / GB(asia / us 間)。
処置① 同 region に新 AR 作成、image を gcrane copy または skopeo で移行 → ② GKE node の Docker config を新 AR に変更 → ③ 旧 AR は30 日 retention 後削除 → ④ Multi-region AR(例:asia)も検討(同一 multi-region 内は egress free)。
教訓「AR は global」と誤解されがち、実態はregion / multi-region に紐づくGKE と同 region または同 multi-region に置く。
検知Cloud Billing export で sku.description LIKE "%Network Inter-Region%" を集計、急増を検知。
⚠️ 11.1.5 Cleanup Policy で本番 image が一括削除、production down
症状朝、本番 GKE で ImagePullBackOff 大量発生。確認すると本番で使用中の v1.5.3 image が AR から消えていた。
原因「未使用 image を削除」と policy を投入:condition: { olderThan: "30d" }全 image 30 日超を delete。本番で長期稼働している stable version も対象に。dry-run 怠った
処置① 緊急再 build & push(CI を retro-run) → ② cleanup policy を修正:most_recent_versions: { keep_count: 10 }condition: { tag_state: "UNTAGGED", olderThan: "30d" }(タグなしのみ削除) → ③ protect tagrelease-* tag を絶対削除しない。
教訓cleanup policy は必ず dry-runを 7 日。keep_count + UNTAGGED 条件 + protect tag の 3 重防御。本番で使用中の image を特定する Cloud Asset Inventory query を組み合わせるとさらに安全。
検知AR の DELETE イベントを Audit Log で監視、release-* tag を含む削除は即時 alert。
⚠️ 11.1.6 Docker Hub 認証なし → rate limit で全 build fail
症状朝一の build wave で toomanyrequests: You have reached your pull rate limit が頻発、全 CI 凍結。
原因base image FROM python:3.11 を Docker Hub から直接 pull。匿名 IP は 6h で 100 pull制限。社内全プロジェクトの Cloud Build VM が共有 NAT IP を使用していたため、全社合算で上限突破。
処置AR Remote Repository を作成(upstream: Docker Hub、Docker Hub の paid auth 設定)→ ② Dockerfile を FROM ASIA-DOCKER.PKG.DEV/PRJ/dockerhub-cache/python:3.11 に書き換え → ③ AR Virtual Repository で内製 + remote を 1 endpoint に集約。
教訓外部 registry に直接依存しない。AR Remote Repositoryで透過 cache + auth。Cloud Build の egress NAT IP は project 横断で共有される事実に注意。
検知build 失敗 log を grep して toomanyrequests 件数を Monitoring に出し、1 件で alert。
💰 11.1.7 Vulnerability Scanning $0.26/image でコスト垂れ流し
症状請求書の「Container Analysis」が月 ¥250,000。Artifact Analysis (旧 Container Scanning) 課金。
原因Cleanup policy 不在で月 100,000 image push、各 image が初回 push 時に automatic scan。$0.26 / image × 100,000 = $26,000 ≒ ¥4,000,000 のはずが auto scan は30 日以内アクセスのみ課金で実質 ¥250,000 に。
処置Cleanup policy で push 数を月 1 万に圧縮 → ② on-demand scan モードに切り替え(release branch のみ scan、PR は scan しない)→ ③ Continuous Validation は本番 cluster のみ。
教訓scan はimage 数に比例。PR 大量の monorepo では特に注意。「scan するに値する image」だけを scan する設計。
検知BigQuery billing export で sku.description LIKE "%Container Analysis%" を月次トレース。
⚠️ 11.1.8 Virtual Repository の priority ミスで dependency confusion 攻撃
症状セキュリティスキャンで「内製 package company-internal-utils の悪意ある版が AR に存在」を検知。
原因AR Virtual Repository の構成:priority 1: pypi (remote)priority 2: company-internal (standard)。攻撃者が PyPI に同名の悪意 package を公開、Virtual Repo はpriority 1 の pypi を先に見るため、悪意版を pull。
処置priority を逆転priority 1: company-internalpriority 2: pypi → ② scope pattern で内製 prefix(company-*)を pypi 側から除外 → ③ requirements.txt に hash pin を付与(--require-hashes)。
教訓Virtual Repo の priority と scope はdependency confusion 攻撃の主戦場内製 prefix を priority 1 + scope 限定が標準。
検知AR への push log で company-* prefix package が remote 起源で記録されたら alert。
⚠️ 11.1.9 Multi-region AR の replication 遅延で 1 region だけ image 不在
症状Cloud Deploy が global multi-region に同時 deploy。europe-west1 で ImagePullBackOff、他は OK。10 分後に解消。
原因AR の multi-region(例:asiaus)はregion 間 replication が非同期。push 後すぐ別 region から pull するとNotFound。Cloud Deploy は image 存在を待たず deploy 開始。
処置push 後 wait ステップを Cloud Build に追加(gcloud artifacts docker images describe を各 region から poll) → ② または各 region に独立 ARを持ち、image を明示 copy → ③ Cloud Deploy の verify で image pull を最初に確認。
教訓AR multi-region は「いずれ整合」強整合ではない。push 直後の deploy は明示 wait or per-region push
検知deploy 失敗の ImagePullBackOff を分単位で count、push 直後 N 分以内ピークを検知。
⚠️ 11.1.10 IAM が緩く organization 外の reader 権限が漏れ、内部 image が公開
症状外部リサーチャーから「artifactregistry.repositories.downloadArtifactsallAuthenticatedUsers に付与されている」と指摘。Google アカウントを持つ全世界の人が image pull 可能。
原因新人が「社内全員に開放」のつもりで allAuthenticatedUsers(= Google 認証済み全世界)を roles/artifactregistry.reader に bind。allUsers(公開)よりは限定的だが、外部の不特定多数に開放。
処置IAM binding を即時削除 → ② 社内開放はGoogle Workspace ドメインdomain:company.com) orgroupgroup:engineers@company.com) → ③ VPC SC でさらに organization 外からのアクセスを遮断 → ④ image に脆弱性 / secret が含まれていないか緊急スキャン。
教訓allUsers / allAuthenticatedUsers は本番 IAM では禁忌group / domain 限定 + VPC SCが標準。新人教育で必ず徹底。
検知Organization Policy の iam.allowedPolicyMemberDomains で外部 principal を全面禁止。Cloud Asset Inventory + Recommender で「広い IAM」を週次レポート。

11.2 Artifact Registry コスト構造の解剖

11.2.1 主要コンポーネント別の課金

コンポーネント課金単位備考
Storage$0.10 / GB / 月(最初の 0.5 GB 無料)image / package / manifest の合計サイズ
Network egress(同 region)無料同 region GKE / Cloud Run から pull は free
Network egress(同 multi-region 内、例 us-central1 ↔ us)無料multi-region 内の region 間も free
Network egress(multi-region 間 / cross-region)$0.02 / GB(同大陸)、$0.05〜0.12 / GB(大陸間)大陸跨ぎ pull は要警戒
Network egress(internet / Cloud Interconnect)$0.085〜0.12 / GB外部 CDN や on-prem からの pull
Vulnerability scan(automatic)$0.26 / image(push 時 1 回 + 30 日以内アクセスあるもの)access ないと re-scan されない
Vulnerability scan(on-demand)$0.26 / scan明示的に scan 要求した時のみ
Remote Repository upstream pullupstream の課金 + AR storageDocker Hub などの paid plan は別途
「Container scanning is priced at $0.26 per container image scanned, charged once per image at push time. Re-scans for ongoing vulnerability monitoring are included in the initial price for 30 days after the most recent access.」 — Artifact Registry pricing

11.2.2 Storage コスト試算

▼ 月あたり storage コスト試算(free 0.5 GB 引いた後) 10 GB → 9.5 × $0.10 = $ 0.95 / 月 100 GB → 99.5 × $0.10 = $ 9.95 / 月 1 TB → 1023.5 × $0.10 = $ 102.35 / 月 ≒ ¥ 16,000 5 TB → 5119.5 × $0.10 = $ 511.95 / 月 ≒ ¥ 80,000 10 TB → 10239.5 × $0.10 = $1024.0 / 月 ≒ ¥160,000 ▼ cleanup policy 設定後(最終 30 日のみ keep)の典型サイズ monorepo CI: 1 PR = 500 MB × 1000 PR/月 × 1 month = 500 GB → $50 / 月(policy あり) vs $750 / 月(policy なしで 1.5 年放置)

11.2.3 Region vs Multi-region のコスト差

location 種別storage 単価備考
Regionasia-northeast1$0.10/GB単一 region 内可用性
Multi-regionasia / us / eu$0.10/GBregion 間 replication 込み(料金同じ)
Dual-regionnam4 / eur4 等$0.10/GB(同レート)2 region 間で同期
💡 BP:location 選定の指針
  • 単一 region で GKE が動く → 同 region に AR(最安、最速)
  • multi-region に GKE deploy(asia 内) → multi-region asia AR(料金同じ、replication 自動)
  • 大陸跨ぎ deploy(asia + us + eu) → 各大陸ごとに独立 AR + Cloud Build で push、egress を回避

11.3 コスト肥大化の典型パターン 5 件

💰 パターン A — Cleanup Policy 不在で storage 線形増加

1 PR = 500 MB image × 1000 PR/月 を 1 年保持で 6 TB、月 ¥96,000。対処:cleanup policy(UNTAGGED & olderThan: 30d + keep_count: 10 for tagged)を新 repo テンプレに組み込む。

💰 パターン B — Cross-region pull egress

GKE と AR が異 region で、daily pod restart の度に GB 単位 pull。対処:同 region or 同 multi-region に AR を寄せる。移行は gcrane copy / skopeo copy で実施。

💰 パターン C — Vulnerability scan が PR 全 image で発火

PR push 毎に scan が走り $0.26 × N。対処:「PR は scan 不要、main branch だけ scan」と運用ルール化、push 制限。on-demand scan モードに切り替え。

💰 パターン D — Tag 大量で metadata API quota 圧迫

tag 操作は metadata API quota を消費。1 image に 100 tag はquota だけでなく list 操作のレイテンシも悪化。対処:tag は commit_sha + semver + env の 3 種類以内。

💰 パターン E — Remote Repository に upstream 認証なしで rate limit + fail retry

Docker Hub anonymous で push 大量、rate limit fail → 再 build。対処:Docker Hub は paid plan で AR Remote Repository に auth 設定、または quay.io / ECR public など制限ゆるい mirror に切替。

11.4 最適化テクニック 8 個

  1. Cleanup Policy をテンプレ化:「UNTAGGED & 30d 超 → 削除」「tagged は keep_count 10」「release-* は protect」の 3 ルール。新 repo 作成時に Terraform module で自動付与。
  2. Tag Immutability を有効化:latest 上書きを禁止、digest pin 運用に統一。
  3. 同 region に AR を寄せる。GKE / Cloud Run / Cloud Build と同 location にして egress を free に。
  4. Remote Repository で外部 dependency を auth 付き cache。Docker Hub / PyPI / Maven Central / npm を AR 経由で pull。
  5. Virtual Repository内製 priority 1 + scope 限定、dependency confusion 防止。
  6. Vulnerability scan を on-demand に切替。PR push 毎の auto scan を停止し、main / release branch のみ scan。
  7. Lifecycle 監視:storage size を月次レビュー、cleanup policy の dry-run 結果を四半期で見直し。
  8. IAM を group / domain 限定 + VPC SCallUsers / allAuthenticatedUsers は Organization Policy で全面禁止。
💡 BP:Cleanup Policy の安全テンプレ
# 1) UNTAGGED かつ 30 日経過 → 削除(安全) { "name": "delete-untagged-30d", "action": { "type": "Delete" }, "condition": { "tagState": "UNTAGGED", "olderThan": "2592000s" } } # 2) Tagged で各 image は最新 10 個まで keep { "name": "keep-recent-10", "action": { "type": "Keep" }, "mostRecentVersions": { "keepCount": 10 } } # 3) release-* tag は絶対保護 { "name": "protect-release-tags", "action": { "type": "Keep" }, "condition": { "tagState": "TAGGED", "tagPrefixes": ["release-", "v"] } } # 投入時:必ず --dry-run で 7 日観察 gcloud artifacts repositories set-cleanup-policies REPO \ --location=LOCATION \ --policy=policy.json \ --dry-run # ← 必須 # Cloud Logging で dry-run 削除予定 image を確認、問題なければ gcloud artifacts repositories set-cleanup-policies REPO \ --location=LOCATION \ --policy=policy.json --no-dry-run

11.5 監視・アラート設計

11.5.1 監視すべき主要 metric

metric説明SLI / alert 例
artifactregistry.googleapis.com/repository/sizerepo の合計サイズ20% / 月の増加で warn
artifactregistry.googleapis.com/quota/...API quota 使用量80% で warn、95% で critical
artifactregistry.googleapis.com/request_countAPI call 数急増で abuse / loop 検知
response_code="429" countrate limit 到達数1 件で warn(quota or tag 過剰)
vulnerability count(HIGH 以上)Artifact Analysis 結果HIGH 1 件で Slack、CRITICAL で PagerDuty
cleanup policy 削除件数Audit Log から集計急増で「policy 設定ミス」検知

11.5.2 拡大しがちな pattern の早期検知 dashboard 例

▼ BigQuery クエリ例(billing export ベース) -- AR storage の月次推移 SELECT invoice.month, SUM(cost) AS storage_cost, SUM(usage.amount_in_pricing_units) AS gb_month FROM `PRJ.billing.gcp_billing_export_v1_XXX` WHERE service.description = 'Artifact Registry' AND sku.description LIKE '%Storage%' GROUP BY invoice.month ORDER BY invoice.month DESC; -- cross-region egress の検知 SELECT invoice.month, sku.description, SUM(cost) AS egress_cost FROM `PRJ.billing.gcp_billing_export_v1_XXX` WHERE service.description = 'Artifact Registry' AND sku.description LIKE '%Inter-Region%' GROUP BY invoice.month, sku.description ORDER BY egress_cost DESC;

11.5.3 ガバナンス指針

新 repo 作成
Terraform module 経由必須、cleanup policy + Tag Immutability + group IAM がデフォルト
IAM ガード
Organization Policy で iam.allowedPolicyMemberDomainsallUsers / allAuthenticatedUsers 禁止
Vulnerability
HIGH / CRITICAL は週次レポート + Binary Authorization Continuous Validation
コスト
月 ¥10,000 超の repo は名指しで owner にメール、四半期レビュー
tag 監査
1 image につき tag 5 個以上は WARN、10 個以上は強制削除
🔑 試験ポイント(Section 11 要点)
  • AR の主要コストは storage($0.10/GB/月)+ cross-region egress。同 region なら egress 無料
  • Cleanup Policy なし = 青天井。必ず dry-run 後に本番投入
  • Vulnerability scan は $0.26 / image(push 時 + 30 日以内 access があるもの)
  • Tag Immutability + digest pinが rollback の唯一安全策。:latest は本番禁止
  • Virtual Repository は内製 priority 1 + scope 限定で dependency confusion 防止
  • multi-region AR の region 間 replication は非同期、push 直後の deploy は注意
  • IAM はgroup / domain 限定 + VPC SCallUsers / allAuthenticatedUsers 禁止
  • metadata API quota:60,000 req / min / region / project。tag 過剰で枯渇

8.4 次のステップ