Google Cloud ハンズオン教科書|2026-08 版
第 16 章 試験ガイド 4.1 試験ガイド 6.2 試験ガイド 5.1

IaC と CI/CD — Terraform・Cloud Build・デプロイ戦略

インフラをコードにし、リリースを安全にする

この章で学ぶこと

試験ガイド対応: セクション 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 回目以降の実行は差分だけが適用されます。

構成ファイル(.tf) あるべき状態 state(tfstate) 現在の状態の記録 実行計画(plan) 追加 / 変更 / 削除 Google Cloud 実リソース VPC・VM など plan が読む plan が読む apply API 呼び出し apply の結果で state を更新
図 16-1 Terraform の適用サイクル。plan は「構成」と「state」の 2 つを読んで差分を計算するだけで実環境に触れない。実環境を変えるのは apply だけで、その結果が state に書き戻される。だから state が壊れると差分計算そのものが狂う。

state を Cloud Storage に置く — チーム開発の前提

state は既定でローカルの terraform.tfstate に保存されますが、複数人で同じインフラを管理すると「各自の state がバラバラ」という事故が起きます。公式ドキュメントの推奨は Cloud Storage バケットをリモートバックエンドにすることです。バケットには次の設定を入れます。

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 バックエンドとの使い分けとして覚えておきましょう。

試験の視点: セクション 4.1 は「技術プロセスの分析と定義」— SDLC や CI/CD をアーキテクトとして整備する観点です。「環境ごとに構成がずれていく」「本番変更に監査可能な履歴がない」という問題記述が出たら、答えの軸は IaC(Terraform)+ Git + パイプライン化です。コンソールの手作業を増やす選択肢や、監査ログを見るだけの選択肢は根本対策になりません。

CI/CD パイプライン — Cloud Build・Artifact Registry・Cloud Deploy

Cloud Build — ステップの連なりとしてビルドを書く

Cloud Build は Google Cloud のマネージド CI/CD 実行基盤です。ビルドはステップの列として YAML(または JSON)の構成ファイル、通称 cloudbuild.yaml に書きます。重要な仕組みは次のとおりです。

料金は消費したビルド分に対して発生し、各請求先アカウントに月 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 つ。

ストレージは請求先アカウントあたり 0.5 GiB まで無料、以降は従量課金です(2026-08 時点)。同一ロケーション内のデータ転送は無料なので、リポジトリはデプロイ先と同じリージョン(本書では asia-northeast1)に作るのが基本です。

開発者 GitHub リポジトリ git push トリガー発火 Cloud Build(cloudbuild.yaml のステップ列) ① docker build イメージを作る ② docker push AR へ送る ③ run deploy Run へ反映 各ステップは 1 つのコンテナとして直列実行(/workspace を共有) Artifact Registry イメージの保管 Cloud Run 新リビジョン作成 push deploy pull
図 16-2 ハンズオン 16-3 で組む CI/CD パイプラインの全体像。push を検知したトリガーが cloudbuild.yaml の 3 ステップを順に実行する。ステップは同じ /workspace を共有するので、①で作ったイメージを②③がそのまま扱える。

Cloud Deploy — 環境をまたぐ「配信」を管理する

ビルドまでが CI だとすると、その成果物を dev → staging → prod と順番に届けていく継続的デリバリーを担うのが Cloud Deploy です。デプロイ先ランタイムは GKE と Cloud Run(および GKE attached クラスタ)で、内部ではレンダリング・デプロイ・検証に Skaffold を使います。概念の対応を押さえましょう。

デプロイ戦略としては、単純に全量を置き換える standard と、一部から段階的に広げるカナリアをサポートし、カナリアの割合は任意の整数パーセントの並びで指定できます(小数は不可)。承認要求は Pub/Sub 通知と連動するので、チャットや ITSM への組み込みも可能です。

リリース レンダリング済み dev ターゲット staging ターゲット 承認(approval) 人手のゲート prod ターゲット rollout promote promote 承認後 rollback
図 16-3 Cloud Deploy の配信パイプライン。リリースはターゲットの順序に沿ってプロモーションされ、本番前に承認ゲートを挟める。ロールバックは特別な操作ではなく「直前に成功したリリースをそのターゲットへ再ロールアウトする」ことである点に注目。

デプロイ戦略 — ローリング / Blue-Green / カナリア

「新しいバージョンをどう本番に入れ替えるか」は、試験セクション 6.2(デプロイとリリースの管理)の中心テーマです。3 つの基本戦略の仕組みとトレードオフを図で比べます。

ローリング更新 — 少しずつ置き換える v2 v2 v1 v1 maxSurge / maxUnavailable で置換ペースを制御 時間経過で v1 が v2 に置き換わる Blue / Green — 2 面を用意して一括切替 ロードバランサ Blue(v1)稼働中 Green(v2)待機 100% 切替後 100% 切替は一括・瞬時 戻すのも一括 = 即ロールバック カナリア — 一部のトラフィックで検証 ロードバランサ v1(安定版) v2(カナリア) 90% 10% 指標が健全なら比率を上げ 最終的に 100% へ
図 16-4 3 つのデプロイ戦略でトラフィックの移り方がどう違うか。ローリングは「台数」を徐々に、カナリアは「トラフィック比率」を徐々に動かす。Blue-Green だけが 2 面分のリソースを常に持ち、その代わり切替と切り戻しが一瞬で終わる。
観点ローリング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
試験の視点: 問題文の要件語彙から戦略を逆引きします。「ダウンタイム許容不可 + 問題があれば即座に切り戻し」→ Blue-Green。「本番トラフィックの一部でまず検証」→ カナリア。「追加リソースを抑えて順次更新」→ ローリング。もう 1 つの隠れた判定軸が新旧バージョンの共存です。ローリングとカナリアは移行中に v1 / v2 が同時にリクエストを受けるため、DB スキーマや API の前方・後方互換性が保てない変更では Blue-Green(または互換レイヤの追加)に倒します。

テストをパイプラインのどこに置くか

試験セクション 5.1 では、開発チームに助言する立場として単体 / 統合 / 負荷のテストフレームワークが問われます。CI/CD に載せるときの置き場所はこう整理します。

ハンズオン

ハンズオン 16-1|Terraform で VPC と VM を作って壊す

カスタムモード VPC + サブネット + e2-micro VM の 3 リソースを Terraform で作成し、plan の差分表示を観察してから destroy で完全に消します。所要 20〜30 分。費用の目安: e2-micro 1 台を 30 分ほど起動するだけなので数円程度です(外部 IP は付けません)。Cloud Shell(Terraform プリインストール済み)での実行を前提とします(ローカルの gcloud + Terraform でも可)。

  1. 作業ディレクトリを作り、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
  }
}
  1. 初期化 → 計画 → 適用の順に実行する
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-2|Terraform state を Cloud Storage バケットへ移す

16-1 のローカル state を GCS バックエンドへ移行し、チーム共有可能な構成にします。所要 10 分。費用の目安: state は数 KB なのでストレージ課金は実質 0 円です。

  1. 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
  1. ~/tf-handson/backend.tf を作成する
# backend.tf
terraform {
  backend "gcs" {
    bucket = "PROJECT_ID-tfstate"
  }
}
  1. 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-3|Cloud Build から Cloud Run へ自動デプロイする

図 16-2 のパイプラインを組みます。コンテナをビルドして Artifact Registry に push し、Cloud Run へデプロイする一連を cloudbuild.yaml に記述して実行、最後にリビジョン切替でロールバックも体験します。所要 30〜40 分。費用の目安: Cloud Build は月 2,500 ビルド分・Artifact Registry は 0.5 GiB までの無料枠内、Cloud Run も無料枠内に収まり実質無料です(2026-08 時点)。

  1. 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
  1. 同じディレクトリに Dockerfile を作成する(Cloud Run の既定ポート 8080 で静的ページを返すだけの最小構成)
# Dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY index.html .
CMD ["python", "-m", "http.server", "8080"]
  1. 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'
  1. ビルドに使うサービスアカウントへ Cloud Run へのデプロイ権限を与える。コンソールで Cloud Build の [設定] を開き、Cloud Run(Cloud Run 管理者)とサービス アカウント(サービス アカウント ユーザー)のステータスを有効にする(公式ドキュメントの手順どおり。gcloud で個別ロールを付与しても同じ)
  2. ビルドを実行し、デプロイされた 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>
  1. 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 のソース置き場バケットが残っていれば確認して削除

つまずきポイント

state を Git にコミットしてしまう / ローカル state を失う: state には作成済みリソースの詳細(機密になり得る値を含む)が平文で入ります。リポジトリには絶対にコミットせず、.gitignore に *.tfstate* を入れた上で GCS バックエンド + バージョニングに置くのが基本形です。逆にローカル state のまま端末を初期化すると、リソースは生きているのに Terraform が「何も管理していない」状態になり、手作業での片付けを強いられます。
Cloud Build からのデプロイが権限エラーで落ちる: ビルド自体は通るのに最後の gcloud run deploy ステップで PERMISSION_DENIED になるのは、ビルドに使うサービスアカウントに Cloud Run 管理者とサービス アカウント ユーザーのロールが無いのが定番原因です(ハンズオン 16-3 の手順 4)。「Cloud Build は自分の権限ではなくサービスアカウントの権限で動く」ことを思い出してください(第 2 章)。
手動 submit で $COMMIT_SHA が空になる: $COMMIT_SHA はトリガー経由で Git のコミット情報があるときに入る変数です。gcloud builds submit の手動実行ではソースが Git 由来ではないため空になり、イメージタグが hello: のようになってビルドが失敗します。手動実行を含むパイプラインでは $BUILD_ID を使うか、独自 substitution を渡します。
消し忘れ課金と削除の順序: Artifact Registry はイメージを push するたびに履歴が積み上がり、無料枠 0.5 GiB を超えると課金されます。学習後はリポジトリごと削除するか、クリーンアップポリシーで古いタグを自動削除しましょう。また Terraform の後片付けは必ず「terraform destroy → state バケット削除」の順で。先にバケットを消すと state を失い、destroy が実行できなくなります。

理解度チェック

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 共有はできても、レビューを経ない適用を止められません。

まとめと次章へ

次の第 17 章では、ここまでに設計してきた個々の要素を「既存システムをクラウドへ運ぶ」文脈に束ねます。移行パターン、RTO / RPO と DR 設計、そしてコスト最適化 — PCA のケーススタディに直結する章です。

参考リンク: