TerraformでGCPのVPCとCompute EngineインスタンスをIaC管理する方法|google providerの設定とリソース設計の実践手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Terraform > TerraformでGCPのVPCとCompute EngineインスタンスをIaC管理する方法|google providerの設定とリソース設計の実践手順
「TerraformでAWSは触ったことがあるのに、GCPへの展開になった途端どこから手をつければいいかわからない」
こういう状況に陥ることは珍しくない。AWSとGCPではプロバイダーの構造や認証方法が異なるため、同じHCLの感覚でそのまま移行しようとするとつまずく箇所が必ず出てくる。

この記事では、TerraformのGoogle Cloudプロバイダー(google provider)を使ってVPC・サブネット・ファイアウォール・Compute Engineインスタンスを一から定義し、terraform apply で実際にリソースを作成する手順を解説する。認証設定の落とし穴、AWSとの設計の違い、よくあるエラーの切り分けまでカバーする。

この記事のポイント

・google providerの認証はService Accountキーファイルで行う
・VPCはAWSと違いリージョンを持たず、サブネットがリージョン単位になる
・Compute Engineはゾーン指定が必須でrequired_providers設定と一緒に確認する
・APIの有効化忘れと権限不足が最頻出エラーの2大原因


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

GCPとTerraform(google provider)の基礎知識

TerraformでGCPを操作するには、HashiCorp公式パートナーのgoogle providerを使う。2024年以降のバージョン(5.x系)が安定しており、ほぼすべてのGCPリソースに対応している。

GCPとAWSのTerraformプロバイダーで最初に戸惑う違いはプロジェクトの概念だ。AWSではアカウント単位でリソースが管理されるが、GCPではアカウントの下に「プロジェクト」という単位があり、リソースは必ずどこかのプロジェクトに属する。Terraformのリソース定義でも `project` 引数が頻出するため、最初にプロジェクトIDを変数化しておくと後が楽になる。

また、GCPはサービスごとにAPIを有効化する必要がある。Compute EngineのVPCやインスタンスを作成するには、まず `compute.googleapis.com` を有効化しておくことが必須だ。これを忘れると apply 実行時に403エラーが返ってきて初心者は首をかしげることになる。

google providerの認証設定

1. GCPプロジェクトの準備とgcloudの設定

作業前に以下が必要だ。

・GCPプロジェクトが作成済みであること
・Google Cloud SDK(gcloud CLI)がPCにインストール済みであること
・請求アカウントがプロジェクトに紐付けられていること(Compute Engineの作成には請求設定が必要)

gcloudの初期設定はこのコマンドで行う。

# gcloudへのログインとプロジェクト設定 gcloud auth login gcloud config set project [プロジェクトID] # 設定確認 gcloud config get-value project # Compute Engine APIを有効化(必須) gcloud services enable compute.googleapis.com \ --project=[プロジェクトID]

2. Terraform用サービスアカウントの作成

Terraformが使用する認証情報はサービスアカウントのキーファイルで管理する。個人のgcloudセッションをそのまま使う「Application Default Credentials(ADC)」方式もあるが、CI/CDパイプラインへの展開を見据えてサービスアカウントを最初から用意しておくのが実務上の正解だ。

# サービスアカウントの作成 gcloud iam service-accounts create terraform-sa \ --display-name="Terraform Service Account" \ --project=[プロジェクトID] # Compute管理者ロールを付与 gcloud projects add-iam-policy-binding [プロジェクトID] \ --member="serviceAccount:terraform-sa@[プロジェクトID].iam.gserviceaccount.com" \ --role="roles/compute.admin" # サービスアカウントを使った操作に必要なロールも付与 gcloud projects add-iam-policy-binding [プロジェクトID] \ --member="serviceAccount:terraform-sa@[プロジェクトID].iam.gserviceaccount.com" \ --role="roles/iam.serviceAccountUser" # JSONキーの発行 gcloud iam service-accounts keys create terraform-key.json \ --iam-account=terraform-sa@[プロジェクトID].iam.gserviceaccount.com

発行した `terraform-key.json` はGitに絶対にコミットしないこと。.gitignoreに必ず追加する。本番環境ではGCP Secret ManagerやTerraform Cloud Variablesでの管理を検討する。

3. required_providersの設定

プロジェクトディレクトリにHCLファイルを作成する。

# versions.tf terraform { required_version = ">= 1.5" required_providers { google = { source = "hashicorp/google" version = "~> 5.0" } } }

# provider.tf provider "google" { credentials = file("terraform-key.json") project = var.project_id region = var.region }

# variables.tf variable "project_id" { type = string description = "GCPプロジェクトID" } variable "region" { type = string default = "asia-northeast1" } variable "zone" { type = string default = "asia-northeast1-b" }

`terraform init` を実行するとgoogle providerがダウンロードされる。

$ terraform init Initializing the backend... Initializing provider plugins... - Finding hashicorp/google versions matching "~> 5.0"... - Installing hashicorp/google v5.40.0... Terraform has been successfully initialized!

VPC・サブネット・ファイアウォールのリソース定義

1. google_compute_networkでVPCを定義する

AWSとGCPのVPCには構造上の大きな違いがある。GCPのVPCはリージョンを持たず、グローバルリソースとして存在する。サブネットが各リージョンに紐付く設計だ。

# network.tf resource "google_compute_network" "main" { name = "terraform-vpc" auto_create_subnetworks = false # カスタムサブネットモードを使う project = var.project_id }

`auto_create_subnetworks = false` でカスタムサブネットモードにすることを強く推奨する。デフォルト(true)にするとリージョンごとにサブネットが自動生成されてしまい、IPレンジ設計の管理が難しくなる。

2. google_compute_subnetworkでサブネットを設計する

resource "google_compute_subnetwork" "main" { name = "terraform-subnet" network = google_compute_network.main.id region = var.region ip_cidr_range = "10.0.1.0/24" project = var.project_id # 外部IPなしのインスタンスからGCPマネージドサービスへのアクセスを許可 private_ip_google_access = true }

`private_ip_google_access = true` は、外部IPを持たないインスタンスからCloud StorageやCloud SQLといったGCPマネージドサービスにアクセスする際に必要だ。実務では最初から有効にしておくのが無難だ。

3. google_compute_firewallでSSHを許可する

GCPのファイアウォールルールはVPCに紐付くリソースとして別途定義する。AWSのセキュリティグループと異なり、インスタンスに直接付与するのではなくネットワークタグで対象インスタンスを絞り込む設計になっている。

resource "google_compute_firewall" "allow_ssh" { name = "allow-ssh" network = google_compute_network.main.name project = var.project_id allow { protocol = "tcp" ports = ["22"] } source_ranges = ["0.0.0.0/0"] # 本番では管理IPに限定すること target_tags = ["allow-ssh"] # このタグを持つインスタンスにのみ適用 }

ここでのポイントは `target_tags` だ。タグ名を後述のインスタンスの `tags` と一致させることで、そのインスタンスにだけファイアウォールルールが適用される。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、TerraformのGCPプロバイダー設定からVPC・Compute Engine設計・AWSとの比較まで、実務で即使えるスキルを習得できるセミナーを開催しています。
>> Terraform実践セミナーの詳細はこちら

Compute EngineインスタンスのIaC定義

1. google_compute_instanceの基本構成

Compute EngineインスタンスはAWSのEC2に相当するリソースだ。ゾーン(zone)指定が必須な点がEC2との設計上の差異としてよく出てくる。

# compute.tf resource "google_compute_instance" "web" { name = "terraform-web" machine_type = "e2-medium" # vCPU 2 / メモリ4GB zone = var.zone project = var.project_id # ファイアウォールのtarget_tagsと一致させる tags = ["allow-ssh"] boot_disk { initialize_params { image = "debian-cloud/debian-12" size = 20 # ディスクサイズ(GB) type = "pd-standard" } } network_interface { network = google_compute_network.main.id subnetwork = google_compute_subnetwork.main.id access_config { # このブロックを空にすることで外部IPが自動割り当てされる } } }

`machine_type` はAWSの `instance_type` に相当する。`e2-medium`(vCPU 2、メモリ4GB)が開発・検証用途でよく使われる。本番では `n2-standard-2` や `c3-standard-4` など用途に合わせて選択する。

`access_config {}` のブロックを置かない場合はインスタンスに外部IPが割り当てられない(プライベートのみ)。外部からSSHで直接アクセスしたい場合は `access_config {}` ブロックが必要だ。

2. metadata_startup_scriptで初期化処理を組み込む

インスタンス起動時に初期設定を実行するには `metadata_startup_script` を使う。AWSの `user_data` に相当する機能だ。

resource "google_compute_instance" "web" { # ...前述の設定... metadata_startup_script = <<-EOF #!/bin/bash apt-get update -y apt-get install -y nginx systemctl enable nginx systemctl start nginx EOF }

スクリプトが長くなる場合はHCLの `file()` 関数で外部ファイルを読み込む方法が管理しやすい。

metadata_startup_script = file("scripts/startup.sh")

terraform plan・apply・destroyの実践フロー

`terraform.tfvars` でプロジェクトIDを渡す構成にしておくとコマンドがシンプルになる。

# terraform.tfvars project_id = "my-gcp-project-123456"

# planで差分確認 $ terraform plan Terraform will perform the following actions: # google_compute_firewall.allow_ssh will be created + resource "google_compute_firewall" "allow_ssh" { + name = "allow-ssh" + network = "terraform-vpc" ... } # google_compute_instance.web will be created + resource "google_compute_instance" "web" { + machine_type = "e2-medium" + name = "terraform-web" + zone = "asia-northeast1-b" ... } # google_compute_network.main will be created # google_compute_subnetwork.main will be created Plan: 4 to add, 0 to change, 0 to destroy.

# applyで実際にリソースを作成 $ terraform apply -auto-approve google_compute_network.main: Creating... google_compute_network.main: Still creating... [10s elapsed] google_compute_network.main: Creation complete after 16s google_compute_subnetwork.main: Creating... google_compute_subnetwork.main: Creation complete after 14s google_compute_firewall.allow_ssh: Creating... google_compute_instance.web: Creating... google_compute_firewall.allow_ssh: Creation complete after 8s google_compute_instance.web: Creation complete after 22s Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

作成したインスタンスへのSSH接続は gcloud コマンド経由が手軽だ。IAP(Identity-Aware Proxy)を使えば外部IPなしでも接続できる。

# gcloudでSSH接続 $ gcloud compute ssh terraform-web \ --zone=asia-northeast1-b \ --project=my-gcp-project-123456 # 不要になったら全リソースを削除 $ terraform destroy -auto-approve Destroy complete! Resources: 4 destroyed.

AWSとGCPの設計上の違い(Terraform視点)

AWSに慣れているエンジニアがGCPのTerraform設計に移行するときに混乱しやすい点を整理する。
設計項目 AWS(Terraform) GCP(Terraform)
ネットワーク aws_vpc(リージョン単位) google_compute_network(グローバル)
サブネット aws_subnet(AZを指定) google_compute_subnetwork(リージョンを指定)
ファイアウォール aws_security_group(インスタンスに付与) google_compute_firewall(タグで対象を絞る)
仮想マシン aws_instance(AZを指定) google_compute_instance(ゾーンを指定)
マシンスペック instance_type(例: t3.medium) machine_type(例: e2-medium)
認証方式 AWS Profile / IAM Role / 環境変数 Service Account JSON / ADC / 環境変数
OSイメージ指定 ami(例: ami-0abcdef1234567) image(例: debian-cloud/debian-12)
起動スクリプト user_data metadata_startup_script

最も重要な違いはファイアウォールの適用方式だ。AWSではセキュリティグループをネットワークインターフェースに直接付与するが、GCPではVPCレベルのファイアウォールルールにネットワークタグで対象を絞り込む。

この設計の違いを理解しないと、インスタンスのタグとファイアウォールの `target_tags` が一致せず「ファイアウォールを設定したはずなのにSSHが繋がらない」というトラブルに直面する。

トラブルシュート

1. Compute Engine APIが有効化されていないエラー

apply 実行時に以下のようなエラーが出る場合、GCPプロジェクトでAPIが有効になっていない。

Error: Error creating Network: googleapi: Error 403: Compute Engine API has not been used in project [PROJECT_ID] before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview

gcloudコマンドでAPIを有効化して再実行する。

gcloud services enable compute.googleapis.com --project=[プロジェクトID]

Terraform側でAPIの有効化も管理したい場合は `google_project_service` リソースを定義し、Compute Engineリソースに `depends_on` で依存関係を明示する方法もある。

2. サービスアカウント権限エラー

Error: Error creating Instance: googleapi: Error 403: Required 'compute.instances.create' permission for 'projects/[PROJECT_ID]/zones/asia-northeast1-b', forbidden

サービスアカウントに必要なロールが付与されていない。現在の権限を確認して付与する。

# 現在の権限を確認 gcloud projects get-iam-policy [プロジェクトID] \ --filter="bindings.members:terraform-sa@[プロジェクトID].iam.gserviceaccount.com" \ --format="json" # roles/compute.admin を付与 gcloud projects add-iam-policy-binding [プロジェクトID] \ --member="serviceAccount:terraform-sa@[プロジェクトID].iam.gserviceaccount.com" \ --role="roles/compute.admin"

3. リージョン・ゾーン指定の混同

Error: Invalid value for field 'resource.zone': 'asia-northeast1'. Zones must be in the format: 'zone-name' (e.g., 'us-central1-a')

Compute Engineの `zone` にはリージョン名(`asia-northeast1`)ではなくゾーン名(`asia-northeast1-b` など)を指定する必要がある。サブネットの `region` とインスタンスの `zone` を混同しないよう注意する。

東京リージョン(asia-northeast1)で使えるゾーンは `-a`・`-b`・`-c` の3種類だ。

本記事のまとめ

TerraformでGCPのVPCとCompute Engineを定義する際のポイントを整理する。
やりたいこと リソース・設定
VPCを作成する(カスタムサブネット) google_compute_network(auto_create_subnetworks=false)
サブネットを作成する google_compute_subnetwork(regionとip_cidr_rangeを指定)
SSHを許可するファイアウォールを設定する google_compute_firewall(target_tagsでインスタンスを絞る)
Compute Engineインスタンスを起動する google_compute_instance(machine_typeとzoneを指定)
起動スクリプトを実行する google_compute_instance + metadata_startup_script
Terraform用の認証を設定する Service AccountキーJSONをcredentials引数で指定

AWSとGCPの最大の設計上の違いは「ファイアウォールのネットワークタグ方式」と「VPCのグローバル設計」の2点だ。この2点を最初に理解しておくと、apply時のトラブルを大幅に減らせる。

認証情報(terraform-key.json)をGitにコミットしないことと、APIの事前有効化は実務で必ず引っかかるポイントなので、チームのチェックリストに組み込んでおくことを推奨する。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、TerraformのGCPプロバイダー設定からVPC・Compute Engine設計・AWSとの比較まで、実務で即使えるスキルを習得できるセミナーを開催しています。
>> Terraform実践セミナーの詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。