- Terraform の plan / apply ワークフローと state の役割を説明し、state を Cloud Storage で共有する構成を組める
- Cloud Build のビルド構成(cloudbuild.yaml)とトリガー、Artifact Registry・Cloud Deploy の役割分担で CI/CD パイプラインを設計できる
- ローリング / Blue-Green / カナリアの 3 つのデプロイ戦略を、要件(ダウンタイム・ロールバック・コスト)から選び分けられる
- 単体 / 統合 / 負荷テストをパイプラインのどこに置くかを判断できる
- Terraform で VPC + VM を作って壊し、Cloud Build から Cloud Run への自動デプロイを実際に動かす
試験ガイド対応: セクション 4.1(技術プロセスの分析と定義 — SDLC・CI/CD)、6.2(デプロイとリリースの管理)、5.1(開発 / 運用チームへの助言 — テストフレームワーク)
ここまでの章では、リソースを 1 つずつ gcloud やコンソールで作ってきました。実務のアーキテクチャでは、この「手作業」を残したままにしません。インフラの定義をコードにして(IaC)、アプリの変更を自動でビルド・デプロイする(CI/CD)ところまでが設計の範囲です。PCA 試験でも「手作業による環境差分をなくしたい」「リリースの失敗を素早く戻したい」という要件から、Terraform・Cloud Build・デプロイ戦略を選ばせる問題が出ます。この章では IaC → CI/CD → デプロイ戦略の順に積み上げます。
IaC と Terraform — インフラをコードで宣言する
宣言的 IaC の考え方と Terraform のワークフロー
Infrastructure as Code(IaC)は、インフラの構成をコードとして記述し、ツールに実環境との差分を適用させる手法です。手順書と手作業に比べて、(1) 同じ構成を何度でも再現できる、(2) 変更が Git の履歴とレビューに乗る、(3) 適用前に「何が変わるか」を機械的に確認できる、という利点があります。Google Cloud で最も広く使われる IaC ツールが Terraform で、google プロバイダ(ベータ API 用に google-beta)を通じて Google Cloud の API を呼び出します。Cloud Shell には Terraform がプリインストールされており、認証も自動で通るため、追加セットアップなしで始められます。
Terraform の中心は 3 つの登場人物です。構成ファイル(.tf、HCL 形式)が「あるべき状態」、state(状態ファイル)が「Terraform が把握している現在の状態」、そして実環境のリソース。terraform plan は構成と state を突き合わせて「追加 / 変更 / 削除」の実行計画を生成するだけで、実環境には触れません。terraform apply が実際に API を呼んでリソースを作り、結果を state に記録します。2 回目以降の実行は差分だけが適用されます。
state を Cloud Storage に置く — チーム開発の前提
state は既定でローカルの terraform.tfstate に保存されますが、複数人で同じインフラを管理すると「各自の state がバラバラ」という事故が起きます。公式ドキュメントの推奨は Cloud Storage バケットをリモートバックエンドにすることです。バケットには次の設定を入れます。
- オブジェクトのバージョニングを有効化 — state が壊れたとき過去版に戻せる保険
- 公開アクセスの防止と均一なバケットレベルアクセス — state には接続情報などの機密が入り得るため
terraform {
backend "gcs" {
bucket = "PROJECT_ID-tfstate"
}
}
この backend "gcs" ブロックを置いて terraform init -migrate-state を実行すると、既存のローカル state がバケットへ移行されます(ハンズオン 16-2 で実際にやります)。あわせて公式のベストプラクティスでは、リソースを network.tf / instances.tf のような論理単位のファイルに分けること、変数は variables.tf に説明付きで宣言すること、データベースのようなステートフルなリソースには削除保護(lifecycle メタ引数)を付けることが推奨されています。
Infrastructure Manager — Terraform のマネージド実行
Infrastructure Manager(Infra Manager)は、Terraform 構成の適用そのものを Google Cloud に任せるマネージドサービスです。デプロイを作成すると Cloud Build のジョブが起動して terraform init → validate → apply を実行し、state・ログ・作成リソースの一覧をリビジョンとして保存します。適用前に影響を確認するプレビュー機能もあります。「Terraform は使いたいが、実行環境や state 管理を自前で運用したくない」チームの選択肢です。素の Terraform + GCS バックエンドとの使い分けとして覚えておきましょう。
CI/CD パイプライン — Cloud Build・Artifact Registry・Cloud Deploy
Cloud Build — ステップの連なりとしてビルドを書く
Cloud Build は Google Cloud のマネージド CI/CD 実行基盤です。ビルドはステップの列として YAML(または JSON)の構成ファイル、通称 cloudbuild.yaml に書きます。重要な仕組みは次のとおりです。
- 各ステップは 1 つのコンテナ実行 —
nameにビルダーイメージ(公式のcloud-builders、コミュニティ製、自作、Docker Hub の標準イメージ)を指定し、argsでコマンドを渡す。ステップは既定で直列に実行され、waitForで並列化できる /workspaceをステップ間で共有 — 前のステップの成果物を次のステップがそのまま使える- substitution 変数 —
$PROJECT_IDや$COMMIT_SHAなどの組み込み変数と、substitutions:で定義する独自変数(_VAR形式)が使える - タイムアウト — ビルド全体の既定は 60 分、最大 24 時間(2026-08 時点)。
options.machineTypeでより大きいマシンも選べる - ビルドプール — 既定はマネージドなデフォルトプール。VPC 内のリソースへ届く必要があるならプライベートプールを使う
- トリガー — ブランチへの push・タグの push・pull request の 3 種類のイベントでビルドを自動起動できる。GitHub / GitHub Enterprise / GitLab / Bitbucket などのリポジトリを接続し、トリガーとリポジトリ接続のリージョンは一致させる
料金は消費したビルド分に対して発生し、各請求先アカウントに月 2,500 ビルド分の無料枠があります(デフォルトプールの e2-standard-2、2026-08 時点。超過分は 1 分あたり $0.006)。キュー待ち時間には課金されません。学習用途ならまず無料枠に収まります。
Artifact Registry — ビルド成果物の置き場
ビルドしたコンテナイメージやパッケージの保管先が Artifact Registry です。Docker イメージのほか、Java / Node.js / Python のパッケージ、apt / RPM、Go モジュール、Helm チャート、汎用アーティファクトなどを 1 か所で管理できます。旧 Container Registry(gcr.io)の後継で、Google Cloud の推奨コンテナレジストリです。押さえるべき機能は 3 つ。
- リポジトリモード — 自分の成果物を置く standard、上流(Docker Hub など)の依存をキャッシュする remote、複数リポジトリを 1 つのエンドポイントに束ねる virtual
- 脆弱性スキャン — Artifact Analysis と統合し、格納したイメージの既知脆弱性を検出できる
- クリーンアップポリシー — 古いイメージを自動削除してストレージ課金を抑える
ストレージは請求先アカウントあたり 0.5 GiB まで無料、以降は従量課金です(2026-08 時点)。同一ロケーション内のデータ転送は無料なので、リポジトリはデプロイ先と同じリージョン(本書では asia-northeast1)に作るのが基本です。
Cloud Deploy — 環境をまたぐ「配信」を管理する
ビルドまでが CI だとすると、その成果物を dev → staging → prod と順番に届けていく継続的デリバリーを担うのが Cloud Deploy です。デプロイ先ランタイムは GKE と Cloud Run(および GKE attached クラスタ)で、内部ではレンダリング・デプロイ・検証に Skaffold を使います。概念の対応を押さえましょう。
- 配信パイプライン(delivery pipeline) — ターゲットを昇格させる順序の定義
- ターゲット(target) — デプロイ先の環境(dev / staging / prod など)
- リリース(release) — CI の成果物から各ターゲット向けにレンダリングされたマニフェストの束
- ロールアウト(rollout) — リリースを特定ターゲットへ実際に適用する操作
- プロモーション(promotion) — リリースを次のターゲットへ進めること。承認(approval)を必須にして人手のゲートを挟める
- ロールバック(rollback) — 直前に成功したリリースをそのターゲットへ再ロールアウトすること
デプロイ戦略としては、単純に全量を置き換える standard と、一部から段階的に広げるカナリアをサポートし、カナリアの割合は任意の整数パーセントの並びで指定できます(小数は不可)。承認要求は Pub/Sub 通知と連動するので、チャットや ITSM への組み込みも可能です。
デプロイ戦略 — ローリング / Blue-Green / カナリア
「新しいバージョンをどう本番に入れ替えるか」は、試験セクション 6.2(デプロイとリリースの管理)の中心テーマです。3 つの基本戦略の仕組みとトレードオフを図で比べます。
| 観点 | ローリング | Blue-Green | カナリア |
|---|---|---|---|
| 置き換え方 | インスタンスを少しずつ新版に | 新環境を丸ごと用意し一括切替 | 一部トラフィックだけ新版へ |
| 追加コスト | 小(maxSurge の分だけ) | 大(一時的に 2 面分) | 小〜中(カナリア分) |
| ロールバック | 逆方向の更新が必要で遅い | 向き先を戻すだけで即時 | 比率を 0% に戻すだけで即時 |
| 新旧の共存 | あり(互換性必須) | 切替の瞬間以外はなし | あり(互換性必須) |
| 向く場面 | コスト重視の定常リリース | ダウンタイム不可・即時切り戻し要件 | 実トラフィックでの検証・リスク最小化 |
Google Cloud の各ランタイムでの実現方法はこうなります。
| ランタイム | ローリング | Blue-Green / カナリア |
|---|---|---|
| Cloud Run(第 7 章) | 新リビジョンへ既定で 100% 移行 | --no-traffic でデプロイし、gcloud run services update-traffic でリビジョン間の比率を制御。タグ付きリビジョンの専用 URL で事前検証も可能 |
| GKE(第 6 章) | Deployment の標準動作(RollingUpdate) | Cloud Deploy のカナリア戦略、または Service / Gateway の重み付けで実現 |
| MIG(第 4 章) | rolling-action start-update。maxSurge / maxUnavailable でペース制御 | カナリア: 新テンプレートを台数・割合を絞って適用(2 バージョン併走)。Blue-Green: MIG を 2 面作り LB のバックエンドを切替 |
MIG のローリング更新はコマンド 1 つで開始できます。--version の代わりに --canary-version と台数指定を添えれば、新テンプレートを一部のインスタンスだけに適用するカナリアになります。
gcloud compute instance-groups managed rolling-action start-update MIG_NAME \
--version=template=NEW_TEMPLATE_URL \
--region=asia-northeast1
テストをパイプラインのどこに置くか
試験セクション 5.1 では、開発チームに助言する立場として単体 / 統合 / 負荷のテストフレームワークが問われます。CI/CD に載せるときの置き場所はこう整理します。
- 単体テスト — 最も速く安い。すべてのコミット(ビルドの最初のステップ)で実行する。Cloud Build ではテスト実行もビルドステップとして書ける
- 統合テスト — 実サービスに近い環境で依存関係ごと検証する。イメージのビルド後、dev / staging ターゲットへのデプロイ後に実行する。Cloud Deploy のデプロイ後検証(verify)もここに使える
- 負荷テスト — 本番相当の構成に対してリリース前に実行する。本番昇格の承認ゲートの手前に置き、SLO(第 15 章)を満たせるかで合否を決める
- カナリア分析 — テストの最終段。実トラフィックの一部で新版のエラー率・レイテンシ指標を観測し、劣化していればロールバックする
ハンズオン
カスタムモード VPC + サブネット + e2-micro VM の 3 リソースを Terraform で作成し、plan の差分表示を観察してから destroy で完全に消します。所要 20〜30 分。費用の目安: e2-micro 1 台を 30 分ほど起動するだけなので数円程度です(外部 IP は付けません)。Cloud Shell(Terraform プリインストール済み)での実行を前提とします(ローカルの gcloud + Terraform でも可)。
- 作業ディレクトリを作り、
main.tfを次の内容で作成する。PROJECT_IDは自分のプロジェクト ID(gcloud config get-value projectで確認)に置き換える
# main.tf
provider "google" {
project = "PROJECT_ID"
region = "asia-northeast1"
zone = "asia-northeast1-b"
}
resource "google_compute_network" "handson" {
name = "tf-handson-vpc"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "handson" {
name = "tf-handson-subnet"
ip_cidr_range = "10.0.1.0/24"
region = "asia-northeast1"
network = google_compute_network.handson.id
}
resource "google_compute_instance" "handson" {
name = "tf-handson-vm"
machine_type = "e2-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
subnetwork = google_compute_subnetwork.handson.id
}
}
- 初期化 → 計画 → 適用の順に実行する
mkdir ~/tf-handson && cd ~/tf-handson # main.tf をここに置く
terraform init # google プロバイダのプラグインを取得
terraform plan # 「Plan: 3 to add, 0 to change, 0 to destroy.」を確認
terraform apply # 差分を見て yes と入力
gcloud compute instances list --zones=asia-northeast1-b
apply が完了すると「Apply complete! Resources: 3 added」と表示され、gcloud で tf-handson-vm が RUNNING で見えます。ここで main.tf の machine_type を e2-small に書き換えてもう一度 terraform plan を実行してみてください。「1 to change」だけが出る — これが宣言的 IaC の差分適用です(apply はしなくて OK)。次のハンズオン 16-2 で state ごと片付けるので、リソースはまだ残しておきます。
後片付け:(16-2 に進まない場合のみ。進む場合は 16-2 の最後でまとめて実行)
terraform destroy # 「Destroy complete! Resources: 3 destroyed.」を確認
16-1 のローカル state を GCS バックエンドへ移行し、チーム共有可能な構成にします。所要 10 分。費用の目安: state は数 KB なのでストレージ課金は実質 0 円です。
- state 置き場のバケットを作り、バージョニングを有効化する(公式推奨: バージョニング + 公開アクセス防止 + 均一なバケットレベルアクセス)
gcloud storage buckets create gs://PROJECT_ID-tfstate \
--location=asia-northeast1 \
--uniform-bucket-level-access \
--public-access-prevention
gcloud storage buckets update gs://PROJECT_ID-tfstate --versioning
~/tf-handson/backend.tfを作成する
# backend.tf
terraform {
backend "gcs" {
bucket = "PROJECT_ID-tfstate"
}
}
- state を移行し、バケットに入ったことを確認する
terraform init -migrate-state # 確認プロンプトに yes
gcloud storage ls gs://PROJECT_ID-tfstate
# default.tfstate が見えれば移行成功。以降の plan / apply はこの state を読む
後片付け: 削除の順序が重要です。先に destroy、その後にバケット削除。逆にすると state を失って Terraform からリソースを消せなくなります。
cd ~/tf-handson
terraform destroy # リソース 3 つを削除
gcloud storage rm --recursive gs://PROJECT_ID-tfstate # state バケットを削除
図 16-2 のパイプラインを組みます。コンテナをビルドして Artifact Registry に push し、Cloud Run へデプロイする一連を cloudbuild.yaml に記述して実行、最後にリビジョン切替でロールバックも体験します。所要 30〜40 分。費用の目安: Cloud Build は月 2,500 ビルド分・Artifact Registry は 0.5 GiB までの無料枠内、Cloud Run も無料枠内に収まり実質無料です(2026-08 時点)。
- API の有効化と Artifact Registry リポジトリの作成
gcloud services enable cloudbuild.googleapis.com \
run.googleapis.com artifactregistry.googleapis.com
gcloud artifacts repositories create handson-repo \
--repository-format=docker --location=asia-northeast1
mkdir ~/run-cicd && cd ~/run-cicd
echo '<h1>Hello CI/CD v1</h1>' > index.html
- 同じディレクトリに
Dockerfileを作成する(Cloud Run の既定ポート 8080 で静的ページを返すだけの最小構成)
# Dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY index.html .
CMD ["python", "-m", "http.server", "8080"]
cloudbuild.yamlを作成する。イメージタグには組み込み substitution の$BUILD_IDを使う(手動実行では$COMMIT_SHAが空になるため)
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t',
'asia-northeast1-docker.pkg.dev/$PROJECT_ID/handson-repo/hello:$BUILD_ID', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push',
'asia-northeast1-docker.pkg.dev/$PROJECT_ID/handson-repo/hello:$BUILD_ID']
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args: ['run', 'deploy', 'hello-cicd',
'--image', 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/handson-repo/hello:$BUILD_ID',
'--region', 'asia-northeast1', '--allow-unauthenticated']
images:
- 'asia-northeast1-docker.pkg.dev/$PROJECT_ID/handson-repo/hello:$BUILD_ID'
- ビルドに使うサービスアカウントへ Cloud Run へのデプロイ権限を与える。コンソールで Cloud Build の [設定] を開き、Cloud Run(Cloud Run 管理者)とサービス アカウント(サービス アカウント ユーザー)のステータスを有効にする(公式ドキュメントの手順どおり。gcloud で個別ロールを付与しても同じ)
- ビルドを実行し、デプロイされた URL へアクセスする
gcloud builds submit --region=asia-northeast1 --config=cloudbuild.yaml .
# STATUS: SUCCESS で完了する
gcloud run services describe hello-cicd \
--region=asia-northeast1 --format='value(status.url)'
curl $(gcloud run services describe hello-cicd \
--region=asia-northeast1 --format='value(status.url)')
# => <h1>Hello CI/CD v1</h1>
- v2 をデプロイしてからロールバックを体験する。
index.htmlを v2 に書き換えて再ビルドすると新リビジョンに 100% が向く。旧リビジョンへ 100% を戻すのがロールバック(リビジョン名は一覧からコピーする)
echo '<h1>Hello CI/CD v2</h1>' > index.html
gcloud builds submit --region=asia-northeast1 --config=cloudbuild.yaml .
gcloud run revisions list --service=hello-cicd --region=asia-northeast1
gcloud run services update-traffic hello-cicd \
--region=asia-northeast1 --to-revisions=REVISION_1_NAME=100
# curl すると v1 に戻っている => これが「即時ロールバック」
本番では手動 submit の代わりに GitHub リポジトリを接続し、push トリガーでこの cloudbuild.yaml を起動します(トリガーとリポジトリ接続のリージョンは一致させる)。
後片付け:
gcloud run services delete hello-cicd --region=asia-northeast1 --quiet
gcloud artifacts repositories delete handson-repo \
--location=asia-northeast1 --quiet
gcloud storage ls # builds submit のソース置き場バケットが残っていれば確認して削除
つまずきポイント
.gitignore に *.tfstate* を入れた上で GCS バックエンド + バージョニングに置くのが基本形です。逆にローカル state のまま端末を初期化すると、リソースは生きているのに Terraform が「何も管理していない」状態になり、手作業での片付けを強いられます。gcloud run deploy ステップで PERMISSION_DENIED になるのは、ビルドに使うサービスアカウントに Cloud Run 管理者とサービス アカウント ユーザーのロールが無いのが定番原因です(ハンズオン 16-3 の手順 4)。「Cloud Build は自分の権限ではなくサービスアカウントの権限で動く」ことを思い出してください(第 2 章)。$COMMIT_SHA はトリガー経由で Git のコミット情報があるときに入る変数です。gcloud builds submit の手動実行ではソースが Git 由来ではないため空になり、イメージタグが hello: のようになってビルドが失敗します。手動実行を含むパイプラインでは $BUILD_ID を使うか、独自 substitution を渡します。理解度チェック
Q1. terraform plan と terraform apply の違いは? state は何のためにある?
plan は構成ファイル(あるべき状態)と state(把握している現状)を突き合わせて実行計画を表示するだけで、実環境を変更しません。実際に API を呼んでリソースを作成・変更・削除し、結果を state に書き戻すのは apply です。state があるからこそ 2 回目以降は差分だけを適用できます。
Q2. Terraform の state を Cloud Storage バケットに置く理由を 2 つ挙げると?
① チームの全員が同じ state を参照でき、各自のローカル state が食い違う事故を防げる。② バケットのバージョニングを有効化しておけば、state が壊れたときに過去の版へ戻せる。あわせて公開アクセス防止と均一なバケットレベルアクセスで保護するのが公式推奨の構成です。
Q3. Cloud Deploy の「リリース」「ロールアウト」「プロモーション」の関係は? ロールバックは何をする操作?
リリースは CI の成果物からレンダリングされたマニフェストの束、ロールアウトはそのリリースを特定ターゲットへ適用する操作、プロモーションはリリースを配信パイプラインの次のターゲットへ進めることです(承認ゲートを挟めます)。ロールバックは「直前に成功したリリースをそのターゲットへ再ロールアウトする」操作です。
Q4.(試験形式)EC サイトが Cloud Run で稼働している。新バージョンをまず本番トラフィックの 10% だけで検証し、問題があれば即座に全トラフィックを旧バージョンへ戻したい。どうする?
A. 新リビジョンへ通常デプロイし、問題があれば再ビルドして戻す B. --no-traffic でデプロイし update-traffic で 10% を割り当て、問題時は 0% に戻す C. MIG のカナリア更新を使う D. 2 つ目の Cloud Run サービスを作り DNS を切り替える
B。Cloud Run はリビジョン間のトラフィック分割を標準機能として持ち、--no-traffic でデプロイしてから任意の比率を割り当て、比率変更だけで即時に戻せます。A は再ビルドの分だけロールバックが遅く、C は Cloud Run ではなく MIG の機能、D は DNS の伝播に依存して即時性がなく管理も二重になります。
Q5.(試験形式)監査要件により「本番インフラのすべての変更は、事前レビューと承認を経て、履歴が追える形で適用されること」が求められた。最も適切な方法は?
A. 変更はコンソールで実施し Cloud Audit Logs で履歴を残す B. Terraform 構成を Git で管理し、Cloud Build のパイプラインで plan の結果をレビュー・承認してから apply する C. 管理者だけに編集ロールを絞って gcloud スクリプトを共有する D. 各メンバーがローカルで terraform apply し、state を共有バケットに置く
B。「事前レビュー + 承認 + 追跡可能な履歴」は IaC + Git + CI/CD パイプラインの組み合わせでしか満たせません。A と C の監査ログ・権限絞り込みは事後追跡や抑止にはなりますが「適用前のレビューと承認」を強制できません。D は state 共有はできても、レビューを経ない適用を止められません。
まとめと次章へ
- Terraform は「構成 + state + 実環境」の差分適用でインフラを管理する。plan は差分表示のみ、apply が実変更。state は GCS バケット(バージョニング有効)に置くのがチーム開発の前提で、マネージド実行が欲しければ Infrastructure Manager
- Cloud Build はコンテナ実行のステップ列としてビルドを記述し(既定 60 分・最大 24 時間、月 2,500 ビルド分の無料枠)、成果物は Artifact Registry(standard / remote / virtual、脆弱性スキャン、クリーンアップポリシー)へ。環境をまたぐ配信とゲートは Cloud Deploy(リリース → ロールアウト → プロモーション + 承認)が担う
- デプロイ戦略は要件語彙で選ぶ: 即時切り戻し + ダウンタイム不可 → Blue-Green / 実トラフィックで検証 → カナリア / コスト重視 → ローリング。ローリングとカナリアは新旧共存に耐える互換性が前提
- テストは単体(毎コミット)→ 統合(デプロイ後検証)→ 負荷(本番昇格前)の順にパイプラインへ組み込み、最後はカナリア分析と SLO で守る
次の第 17 章では、ここまでに設計してきた個々の要素を「既存システムをクラウドへ運ぶ」文脈に束ねます。移行パターン、RTO / RPO と DR 設計、そしてコスト最適化 — PCA のケーススタディに直結する章です。
参考リンク: