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 に届かず謎の hang 、cleanup policy 未設定で AR ストレージ青天井 の 5 つです。
📚 参照する公式ドキュメント
本資料は以下の Google Cloud 公式ドキュメント(2026 年時点)から技術詳細・制限・SLA・ベストプラクティスを抽出しています。各章で都度引用と URL を併記します。
1 Cloud 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)
machineType vCPU Memory per-minute (USD) 1 ビルド 10 分の料金 用途
UNSPECIFIED / E2_MEDIUM 1 4 GB $0.003 $0.03 軽量 CI、無料枠 120 分/日内
E2_STANDARD_2 2 8 GB $0.006 $0.06 標準 web app ビルド
N1_HIGHCPU_8 / E2_HIGHCPU_8 8 7.2-8 GB $0.015-0.016 $0.15-0.16 並列 npm/maven、Docker build 高速化
N1_HIGHCPU_32 / E2_HIGHCPU_32 32 28.8-32 GB $0.032 $0.32 大規模 monorepo、並列テスト
C2_STANDARD_8 (Compute Opt.) 8 32 GB $0.030 $0.30 CPU 律速のコンパイル(Rust/C++)
C2D_STANDARD_16 16 64 GB $0.060 $0.60 巨大 Java/Scala build、AVX-512 系
120 min/日
無料枠(e2-medium 換算)
💰 コスト落とし穴 — 「速い=安い」の罠
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 Pool Private 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 app Private 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–30 region/CPU により可変。上限申請可
Concurrent E2 CPUs (Default, region) 5–100 申請で増加可
Concurrent CPUs (Private Pool, region) 最大 2400(E2/N2D), 300 (C3) region per machine family
ステップ数(steps)/ build 300 固定
image 数 / build 700 固定
args 数 / step 100 各 arg 最大 10,000 文字
env 数 / step 100 各 env 最大 65,536 文字
substitution 数 200 ユーザー定義は _ 始まり必須
tags / build 64 —
build triggers / project 600 固定
secret サイズ 65,536 文字 —
build timeout 最大 24 時間 default 60 分
queueTtl default 3,600 秒 キュー待ちで expire
diskSizeGb 最大 4,000 GB options.diskSizeGb
step 名長 1,000 文字 —
1.7 ⚠️ Cloud Build 事故ケース集
事故 1:Default Pool で Private GKE control plane に届かず、毎回 timeout でビルド枠を食い潰す
症状 build step kubectl apply で i/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/active を quota 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 項目
本番は user-managed SA を必須化 :serviceAccount field を指定し、Secret Manager / Artifact Registry / GKE に必要な最小権限のみ付与。
WIF で外部 CI と連携 :GitHub Actions / GitLab CI から Cloud Build を呼ぶときは SA キー禁止 、Workload Identity Federation で OIDC trust。
Private GKE/SQL/内部 API なら Private Pool :Default Pool で hang する前に必ず Pool 設計。
substitutionOption: MUST_MATCH :typo を build 時に検知させる。ALLOW_LOOSE は絶対禁止。
.gcloudignore を必ず作成 :node_modules/, .git/, dist/, .terraform/ を除外。アップロード時間とコストを劇的に削減。
Docker layer cache を有効化 :Kaniko (gcr.io/kaniko-project/executor) または docker build --cache-from。依存層が変わらない限り再 build スキップ。
multi-stage Dockerfile :build stage(重い)と runtime stage(軽い)を分離、最終 image を distroless / Alpine ベースに。
machineType は「単価×時間」で選定 :軽量 = e2-medium、CPU バウンドコンパイル = C2/C2D、メモリ多用 = N2_HIGHMEM。
secretEnv 一択・ログ漏洩防止 :availableSecrets 以外で機密を扱わない、set +x 強制、Cloud Logging に exclusion filter。
SLSA L3 を素直に取りに行く :options.requestedVerifyOption: VERIFIED と user-managed SA で Cloud Build は自動的に L3 相当の provenance を生成。Binary Authorization と接続して built-by-trusted-builder ポリシーを enforce。
2 Cloud Deploy 徹底解剖
Cloud Deploy は Skaffold をエンジンに用いた managed Continuous Delivery 基盤 です。GKE / Cloud Run / GKE Enterprise への promotion ベースの段階的リリース 、canary / blue-green / standard 戦略 、Verification / Predeploy / Postdeploy hooks 、Approval gate 、Rollback を宣言的に管理します。試験では「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 canary HTTPRoute 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 / region 1,000 —
Targets / project / region 1,000 multiTarget も 1 つとしてカウント
Stages / pipeline 20 serialPipeline.stages の最大長
Child targets / multiTarget 10 並列実行の最大数
Canary phases 5 percentages 配列の最大長(+ stable 自動付与)
Release 保持期間 無期限 手動削除まで GCS snapshot が残存(コスト注意)
Rollout queue 長 1 rollout / target 同時に 2 つは走らせられない
Approval timeout 既定 無期限 放置すると Rollout が永久に pending
executionTimeout 既定 1h / 最大 24h render / deploy / verify の各 Job 単位
verifyTimeout 既定 1h / 最大 24h —
Automations / pipeline 250 auto-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-rollback (kind: 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_SHA や vX.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 app = 1 pipeline :複数 app を 1 pipeline に詰め込まない。リリースサイクルが結合してしまう。
image は必ず digest で pin :--images 渡し時 tag でも digest に解決されるが、CI 側で digest 取得して明示渡しが最も安全。
canary は最低 [10, 50]、verify 必須 :1 phase の即 100% は canary の意味がない。verify 無しの canary も同様。
auto-rollback Automation を導入 :verify 失敗で自動 rollback、prod ダメージ最小化。
approval は複数人 group :単一 approver の休暇で release 凍結を防止。
executionConfigs.serviceAccount を user-managed に :default SA は権限が広い。最小権限 SA を target ごとに作る。
custom Worker Pool を使う :Private GKE / Cloud SQL Private IP がある target は CD 側も Cloud Build Private Pool が必須。
predeploy で smoke test, postdeploy で baking + 通知 :phase の前後に hook を入れて「自動運転」できる pipeline に。
GCS snapshot バケットに lifecycle 設定 :90 日以上経った release artifact は自動削除でコスト抑制。
Binary Authorization と接続 :CD runner SA に roles/binaryauthorization.policyEvaluator、cluster 側で BA を ENABLED、Cloud Deploy 側で requiredAttestors 検証エラーで自動 halt。
3 Artifact 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/...
Maven Java / Kotlin / Scala mvn deploy + artifactregistry-maven-wagon
npm Node.js npm publish + google-artifactregistry-auth
Python PyPI 互換 twine upload / pip install
Helm (OCI) Kubernetes chart helm push chart.tgz oci://...
Apt Debian/Ubuntu .deb apt-get install
Yum RHEL/CentOS .rpm yum install
Go Go modules GOPROXY=https://...artifactregistry.dev
Kubeflow Pipelines ML pipeline packages Vertex AI Pipelines 連携
Generic 任意ファイル(v2025+) gcloud artifacts generic upload
3.2 Repository モード:Standard / Remote / Virtual
モード 役割 典型 use case コスト
Standard 自社 push の artifact を保管(プライマリ) 自社 build の Docker image / 内製ライブラリ ストレージ + ネットワーク
Remote Docker 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 発見時の検知)
対応 OS Debian / Ubuntu / Alpine / RHEL / CentOS / RedHat UBI / 一部 Windows base
SBOM SPDX 形式で自動生成・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: 30d を dry-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。
4 Binary 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 の優先順位
評価順 判定 挙動
1 admissionWhitelistPatterns マッチ即 ALLOW(attestation 不要)
2 clusterAdmissionRules マッチ該当 rule で評価
3 defaultAdmissionRuledefault rule で評価
4 評価モードで判断 ALWAYS_ALLOW / DENY、または REQUIRE_ATTESTATION → 全 attestor verify
5 enforcementMode ENFORCED → 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 での違い
項目 GKE Cloud Run Anthos / GKE Enterprise
有効化 --binauthz-evaluation-modeservice の --binary-authorization cluster registration 時
クラスタ rule 対応 非対応(default rule のみ) 対応
Continuous Validation 対応 非対応 対応
Breakglass pod annotation --breakglass deploy flagpod annotation
system image whitelist 自動(globalPolicyEvaluationMode) 不要(Google managed) 自動
Audit Log Cloud Audit Logs Cloud Audit Logs Connect 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 だけ最後に直列。
5 SLSA 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 ベース)
要件 L1 L2 L3
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 install や pip 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 で構築。
6 Secret & 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
Rotation built-in は通知のみ (Pub/Sub に「rotation 期限が来た」を送る)。新 version の生成はCloud Functions / Workflows で自前実装
Aliases version に latest や prod エイリアスを付与可能
料金 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 HSM Google 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) 1x 低 state を持つ単一インスタンス、メンテ窓あり
Rolling Update 一時的に混在 △(pod 単位) 中 1-1.25x 低 K8s デフォ、後方互換あるなら万能
Blue-Green 完全共存 ×(瞬時切替) 速(router 切戻し) 2x 中 大規模 release、ロールバック即時性重視
Canary 完全共存 ○(%) 速 1-1.2x 中-高 新機能のリスク検証、SaaS 標準
Traffic Splitting / A-B Test 完全共存 ○(細粒度) 速 1.x-2x 高 UX 計測、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 実装
戦略 GKE Cloud Run App Engine
Rolling Deployment RollingUpdate 新 revision の段階 traffic 移行 —(自動 rolling)
Blue-Green Service の selector 切替 / Gateway HTTPRoute traffic 0→100% 瞬時切替 migrate-traffic(瞬時)
Canary Cloud Deploy canary strategy / Gateway HTTPRoute weight traffic split (10/90→50/50→100/0) traffic split(min 1%)
Traffic Splitting Gateway HTTPRoute weight multi-revision traffic split 標準対応(IP / Cookie / Random)
Shadow Istio 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 全章の事故ケース一覧
# 領域 事故 根本原因 即対処
1 Cloud Build Default Pool で Private GKE に届かず hang Pool 選択ミス Private Pool + VPC peering
2 Cloud Build Secret 値がログに平文出力 echo / set -xsecret rotation + ログ削除
3 Cloud Build substitution typo が prod に流出 ALLOW_LOOSE MUST_MATCH 固定
4 Cloud Build .gcloudignore 無しで毎回 800 MB upload テンプレ未設定 .gcloudignore + Kaniko
5 Cloud Build Private Pool quota 枯渇で全社凍結 quota 計画なし quota 増 + alert
6 Cloud Build waitFor ミスで test 前に image push allowFailure 誤用 tag immutable + cleanup
7 Cloud Build legacy default SA で権限昇格穴 SA 移行未対応 user-managed SA 強制
8 Cloud Build queueTtl 1h で深夜 jobs 全 expire quota 不足 queueTtl 延長 + quota 増
9 Cloud Deploy 承認待ちで 2 週間凍結 approval timeout なし group approver + automation
10 Cloud Deploy canary verify 失敗で自動 rollback されず auto-rollback 未設定 Automation rule 設定
11 Cloud Deploy image tag 混乱で再現性疑念 :latest 使用 tag immutable + digest pin
12 Cloud Deploy multi-target 一部失敗で version skew retry 設計なし 全 region rollback automation
13 Cloud Deploy CD runner SA 権限不足で deploy 403 RBAC / IAM 不足 roles/clouddeploy.runner 付与
14 Cloud Deploy Release delete で Rollout 履歴消失 delete vs abandon 混同 abandon + Audit Log export
15 Cloud Deploy deployParameters typo で prod が dev DB を参照 階層マージ理解不足 Target で必ず override
16 AR Cleanup Policy 無しで 5 TB テンプレ未設定 policy + dry-run
17 AR Docker Hub rate limit で全 build fail upstream 認証なし Remote repo に auth 設定
18 AR mutable tag 上書きで rollback 不能 :prod tag 使用 Tag Immutability + SemVer
19 AR リージョン跨ぎ pull で $3000/月 region 選定ミス GKE と同 region に AR
20 AR Cleanup Policy で本番 image 消失 dry-run 怠った --dry-run 必須化
21 AR Virtual repo の優先順位ミスで依存混同攻撃 OSS 先評価 内製 Standard を priority 1
22 BinAuth breakglass 常用でポリシー形骸化 signing CI 未整備 signing 自動化 + P0 incident 化
23 BinAuth CV deny で pod delete → 全停止 CV 仕様誤解 CV は警告のみ、kill 禁止
24 BinAuth DRYRUN 放置で 6 か月未署名通過 運用切替忘れ IaC 管理 + 30 日チェック
25 BinAuth whitelist 緩すぎで任意 image 通過 pattern が広い repo 限定 + 週次レビュー
26 BinAuth KMS key 削除で全署名無効 IAM Deny なし key restore + Deny policy
27 BinAuth multi-attestor 直列で deploy 30 分増 並列化不足 waitFor で並列
28 SLSA provenance 生成のみで検証なし downstream 未実装 cosign verify を CD に
29 SLSA hermetic build 主張するも apt-get install 仕様理解不足 lockfile + base digest pin
30 SLSA signing key を GH Secrets に保存 → 流出 L3 要件違反 KMS 移行 + WIF
31 SLSA self-hosted runner で provenance L2 未達成 managed builder へ移行
8.2 試験で頻出のパターン
🔑 即答マトリクス(試験本番で迷ったらこれ)
問題のキーワード 正解(即答)
Private GKE / Cloud SQL Private IP / VPC SC + Cloud Build Private 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 を流して問題があれば自動 rollback Cloud 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 依存を社内に透過 cache Artifact 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 の段階 release Vertex AI Endpoints の traffic_split / shadow model
build 中 Secret Manager を参照 availableSecrets + secretEnv($$VAR で参照)
8.3 トラブルシュート意思決定フロー
💡 「ビルド/デプロイが失敗した」時の切り分け順序
Cloud Audit Logs を見る :「誰がいつ何を呼んだか」を確定。Cloud Build / Cloud Deploy / Binary Authorization は全て Audit Logs に記録 される。
エラーメッセージで層を特定 :permission denied→IAM、i/o timeout→ネットワーク (Pool)、deny by binary authorization→署名、queueTtl exceeded→quota。
Cloud Build log を確認 :失敗 step / 直前 step を特定、substitution / secretEnv の解決ミスをチェック。
Cloud Deploy Rollout の Job logs を確認 :render / deploy / verify / postdeploy のどの Job で失敗したか。
Binary Authorization の Audit Log を確認 :protoPayload.serviceName=binaryauthorization.googleapis.com でフィルタ、deny 理由を確定。
quota / limit を確認 :gcloud compute project-info describe --project=PRJ、Cloud Monitoring の quota dashboard。
最近の変更を確認 :直近 24h の cloudbuild.yaml / delivery-pipeline.yaml / IAM / VPC firewall の diff。
9 Cloud 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/duration で options.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 Insights で p50_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.yaml の OPA / Conftest CI gate を追加し、env: に TOKEN|SECRET|KEY|PASSWORD を含むキーがあれば拒否 → ④ Secret Manager 経由(availableSecrets + secretEnv)に統一。
教訓 secret は必ず Secret Manager + secretEnv 。set -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 cache (gs://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 policy で storage.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 が残る。
原因 Dockerfile の FROM python:3.11(mutable tag)+ --cache-from で古い base layer を強制再利用 。Cloud Build 側は「Dockerfile 行が変わらない = base layer 再利用」と判断し、新しい upstream patch を pull しない。
処置 ① base image はdigest pin (FROM 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 time vCPU-min × machineType 単価 主要コスト。free tier 月 120 build-min
Artifact storage GCS の通常料金($0.020/GB/月、Standard) gs://PRJ_cloudbuild の log + source upload
Image storage Artifact Registry の料金($0.10/GB/月) Cloud Build 自体ではなく AR 側で課金
Network egress(同 region 内) 無料 AR、GKE 等が同 region なら egress 0
Network egress(cross-region / internet) $0.01〜0.12/GB cross-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 年時点)
machineType vCPU memory 単価($ / build-min) 典型 use case
e2-medium(デフォルト) 1 4 GB $0.003 lint、docs build、小規模 unit test
e2-standard-2 2 8 GB $0.006 中規模 test、軽量 docker build
e2-highcpu-8 8 8 GB $0.016 compile 主体(CPU bound)
e2-highcpu-32 32 32 GB $0.064 monorepo の big build、parallel test
n1-highcpu-8 8 7.2 GB $0.016 legacy。e2 推奨
n1-highcpu-32 32 28.8 GB $0.064 legacy。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」
対処 :Kaniko (gcr.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 個
machineType を job 種別で分離 :lint = e2-medium、unit test = e2-standard-2、compile = e2-highcpu-8、e2e = n2-highmem-4。1 trigger = 1 machineType 原則。
Docker layer cache の徹底 :Kaniko or docker buildx --cache-to=type=registry,ref=$AR/cache,mode=max。dependencies 層を Dockerfile 上で先に COPY/RUN し、source 層を後ろに置く。
Step 並列化(waitFor: ['-']) :依存しない step は並列。Total time が long step に律速されるので、Cloud Build Insights の 「step duration breakdown」 で律速 step を可視化。
Cloud Build Pool sharing :複数 project で同じ Private Pool を共用。iam.serviceAccountUser を build SA に付与し、Pool が他 project から見える状態にする。VPC SC perimeter を同じにする必要あり。
Cache to GCS(multi-build 共有) :Bazel / Gradle / Maven のように外部 cache 対応 build tool は GCS bucket を remote cache に指定。Bazel なら --remote_cache=https://storage.googleapis.com/bucket。
timeoutSeconds の適切な設定 :p99 build time × 1.5。長すぎても短すぎても損失。デフォルト 10 分は monorepo では不足。
Build skip pattern :includedFiles / ignoredFiles で source 変更が無い PR をスキップ。filter: "_HEAD_BRANCH != 'gh-pages'" 等で特殊 branch も除外。
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 + secretEnv 、env 直書き禁止
built-in substitution($BRANCH_NAME)はtrigger 経由でしか展開されない 。manual / API は未定義
cache は build 高速化に有効だが、base image patch を見逃す副作用 。digest pin + 定期 cache flush 必須
10 Cloud 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 yaml で image: 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 verification で kubectl 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.yaml の Pipeline 階層 で 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 denied が clouddeploy 起源で発生したら即 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 policy で clouddeploy.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 min 。executionTimeout 未設定で 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 pool e2-medium 相当 = $0.003 / build-min カスタム実装の job 実行時間
verify job のログ Cloud Logging $0.50 / GB ingest stdout が膨大だと爆発
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 個
Target を「1 環境 × 1 region」に統合 、複数 service を 1 release で進める multi-manifest 構成に。
低頻度 service は Cloud Deploy を使わない 。年数回 deploy 程度なら Cloud Build から直接 kubectl apply で十分。
verify job は fixed size (kubectl logs --tail=50)+ exit code で結果伝達。stdout を巨大にしない。
render / deploy / verify の Cloud Build pool を共有 。execution config の workerPool を統一し、Private Pool の起動コストを 1 つに。
deployParameters は Target で明示 。Pipeline 階層に dev 値を残さない(事故 10.1.5 対策)。
Automation rule で「N 時間 promote されない → abandon」「multi-target 1 つでも fail → 全 rollback」を自動化(事故 10.1.3 / 10.1.4 対策)。
delete ではなく abandon を default 運用。IAM Deny で delete を SRE 限定に。
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 が事故防止セット
11 Artifact 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 add が 429 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_sha、semver、env)に制限 → ③ 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 pin (image: 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 tag で release-* 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-internal、priority 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(例:asia や us)は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.downloadArtifacts が allAuthenticatedUsers に付与されている」と指摘。Google アカウントを持つ全世界の人が image pull 可能。
原因 新人が「社内全員に開放」のつもりで allAuthenticatedUsers(= Google 認証済み全世界)を roles/artifactregistry.reader に bind。allUsers(公開)よりは限定的だが、外部の不特定多数 に開放。
処置 ① IAM binding を即時削除 → ② 社内開放はGoogle Workspace ドメイン (domain:company.com) orgroup (group: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 pull upstream の課金 + AR storage Docker 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 単価 備考
Region asia-northeast1 $0.10/GB 単一 region 内可用性
Multi-region asia / us / eu $0.10/GB region 間 replication 込み(料金同じ)
Dual-region nam4 / 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 個
Cleanup Policy をテンプレ化 :「UNTAGGED & 30d 超 → 削除」「tagged は keep_count 10」「release-* は protect」の 3 ルール。新 repo 作成時に Terraform module で自動付与。
Tag Immutability を有効化 。:latest 上書きを禁止、digest pin 運用に統一。
同 region に AR を寄せる 。GKE / Cloud Run / Cloud Build と同 location にして egress を free に。
Remote Repository で外部 dependency を auth 付き cache。Docker Hub / PyPI / Maven Central / npm を AR 経由で pull。
Virtual Repository で内製 priority 1 + scope 限定 、dependency confusion 防止。
Vulnerability scan を on-demand に切替 。PR push 毎の auto scan を停止し、main / release branch のみ scan。
Lifecycle 監視 :storage size を月次レビュー、cleanup policy の dry-run 結果を四半期で見直し。
IAM を group / domain 限定 + VPC SC 。allUsers / 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.allowedPolicyMemberDomains、allUsers / 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 SC 。allUsers / allAuthenticatedUsers 禁止
metadata API quota:60,000 req / min / region / project 。tag 過剰で枯渇
8.4 次のステップ