概要 #
Google CloudでCompute EngineやCloud Storageなどを利用するには、Projectで対応するAPIを有効にする必要があります。
画面やgcloudコマンドから有効化することもできますが、利用するAPIをTerraformコードで管理すれば、環境構築に必要な設定を再現しやすくなります。
今回はgoogle_project_serviceを使い、3つのGoogle Cloud APIをまとめて有効化します。terraform destroy時の挙動は、disable_on_destroy = falseの側だけを実行し、trueとの違いは仕様として整理します。
この検証ではAPIを有効化しますが、Compute EngineのVMやCloud Storage Bucketなどの実体リソースは作成しません。
Terraformの基本操作は前提としています。Google Cloudの操作にはまだ慣れていない方向けです。
検証すること #
- TerraformからGoogle Cloud APIを有効化できること
- 複数のAPIを
for_eachで管理できること - 有効化したAPIを
gcloudコマンドで確認できること disable_on_destroyによる削除時の違いを理解すること
今回の構成 #
今回の処理の流れは次のとおりです。
APIの有効化はProject単位の設定です。Regionには属しません。
flowchart TB
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
subgraph SU["Service Usage で有効化するAPI"]
Compute["compute.googleapis.com"]
IAM["iam.googleapis.com"]
Storage["storage.googleapis.com"]
end
end
end
有効化には順序が関わります。APIが有効になる前にResourceを作ろうとすると失敗するため、Terraformの依存関係で順序を決めます。
ただし依存関係だけでは足りません。 公式ガイドは「有効化は結果整合性であり、google_project_serviceのプロビジョニングが終わった時点で有効化が保証されるわけではない」としています。反映待ちで後続が落ちるなら、time_sleepなどを挟みます。
sequenceDiagram
participant TF as Terraform
participant SU as Service Usage API
participant API as 対象のAPI
participant Res as Resource
TF->>SU: google_project_service で有効化
Note over SU,API: 反映まで数十秒かかることがある
SU-->>TF: 完了
TF->>Res: Resourceを作成
Note over TF,Res: 依存関係がないと
有効化前に作ろうとして失敗する
disable_on_destroyの扱いにも注意が要ります。指定しなければdestroy後もAPIは有効のままです。trueにすると無効化するので、同じProjectの他の構成へ影響します。
TerraformはGoogle Providerを通してService Usage APIを操作し、指定したProjectで各APIを有効化します。
前提環境 #
- Google Cloud CLI
- Terraform 1.10.0以上、2.0.0未満
- 検証用Google Cloud Project
- 対象Projectを操作できるGoogleアカウント
- Application Default Credentials(ADC)で認証済み
- 対象ProjectでService Usage APIが有効であること
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
APIを有効化するにはserviceusage.services.enable権限が必要です。Google Cloudの事前定義ロールでは、Service Usage Admin(roles/serviceusage.serviceUsageAdmin)などに含まれます。
ADCの設定方法は、前回の記事で確認しています。
使用するTerraformコード #
検証に使用したTerraformコードはこちらです。
ファイル構成 #
01-project-service/
├── README.md
├── versions.tf
├── provider.tf
├── variables.tf
├── main.tf
├── outputs.tf
└── terraform.tfvars.example
versions.tfとprovider.tfは前回と同じ基本構成です。今回は、APIの一覧と削除時の動作を定義するvariables.tf、APIを有効化するmain.tfを中心に確認します。
今回重要なTerraformコード #
variables.tf #
有効化するAPIをset(string)型の変数として定義します。
variable "services" {
description = "Google Cloud API service names to enable. See https://cloud.google.com/service-usage/docs/enabled-service"
type = set(string)
default = [
"compute.googleapis.com",
"iam.googleapis.com",
"storage.googleapis.com",
]
validation {
condition = length(var.services) > 0
error_message = "services must contain at least one API."
}
}
デフォルトでは次のAPIを有効化します。
| API | Service名 | 主な用途 |
|---|---|---|
| Compute Engine API | compute.googleapis.com |
VM、VPC、Firewallなど |
| Identity and Access Management API | iam.googleapis.com |
Service Accountなど |
| Cloud Storage API | storage.googleapis.com |
BucketやObjectなど |
空の集合が渡された場合はValidationでエラーにし、意図せず何も管理しないPlanになることを防いでいます。
APIを削除する際の動作も変数にしています。
variable "disable_on_destroy" {
description = "If true, terraform destroy disables the APIs. If false, APIs remain enabled after destroy."
type = bool
default = false
}
variable "disable_dependent_services" {
description = "If true, disable services that depend on the target APIs when disabling. Use carefully."
type = bool
default = false
}
このサンプルでは、terraform destroy後もAPIを有効なまま残す設定をデフォルトにしています。
main.tf #
google_project_serviceで各APIを有効化します。
resource "google_project_service" "apis" {
for_each = var.services
project = var.project_id
service = each.value
disable_on_destroy = var.disable_on_destroy
disable_dependent_services = var.disable_dependent_services
}
for_eachにvar.servicesを渡すことで、APIごとにgoogle_project_serviceリソースを作成します。
たとえばcompute.googleapis.comは、Terraform State上で次のようなアドレスになります。
google_project_service.apis["compute.googleapis.com"]
ListではなくSetを使用しているため、APIの並び順ではなくService名をキーとして管理できます。
outputs.tf #
Terraformが管理しているAPI名を並べ替えて出力します。
output "enabled_services" {
description = "API service names managed by this sample."
value = sort([for s in google_project_service.apis : s.service])
}
output "project_id" {
description = "Google Cloud Project ID where APIs were enabled."
value = var.project_id
}
Setやfor_eachの処理順に依存せず確認できるよう、sortでAPI名を並べ替えています。
設定 #
ADCでGoogle Cloudへログインする #
ADCを設定していない場合は、対象Projectを操作できるGoogleアカウントでログインします。
gcloud auth application-default login
これは Terraform が使う認証情報で、gcloud コマンド自身の認証とは別です。 あとで gcloud services list を使うので、gcloud auth list でアカウントを確かめ、未認証なら gcloud auth login も実行します。
入力値を設定する #
対象ディレクトリへ移動し、入力値のサンプルをコピーします。
cd Basic-Examples/01-project-service
cp terraform.tfvars.example terraform.tfvars
terraform.tfvarsへ対象のProject IDを設定します。
project_id = "your-project-id"
region = "asia-northeast1"
有効化するAPIを変更する場合は、servicesを上書きします。
services = [
"compute.googleapis.com",
"iam.googleapis.com",
"storage.googleapis.com",
]
Terraformを初期化する #
terraform init
FormatとValidationを確認する #
terraform fmt -check
terraform validate
Validationに成功すると、次のように表示されます。
Success! The configuration is valid.
Planを確認する #
terraform plan
この構成を初めて適用し、3つのリソースがTerraform Stateに未登録なら、追加対象として表示されます。Google Cloud側で既に有効なAPIも追加対象になります。 件数は「新たに有効化されるAPIの数」ではありません。
Plan: 3 to add, 0 to change, 0 to destroy.
すでに有効なAPIが含まれている場合、Google Providerは有効化リクエストを送りません。状態を読み取り、Terraformの管理対象としてStateへ記録します。
このため Apply 後の一覧だけでは、今回新たに有効化したのか、既に有効だったものを取り込んだのかを区別できません。 区別したいなら Apply 前にも同じ一覧を取り、差分を見ます。
Applyする #
Planに問題がなければAPIを有効化します。
terraform apply
確認メッセージにyesを入力します。APIの有効化には数分かかる場合があります。
Apply後は、Terraformが管理するAPI名がOutputへ表示されます。
enabled_services = [
"compute.googleapis.com",
"iam.googleapis.com",
"storage.googleapis.com",
]
project_id = "your-project-id"
GCP側で確認する #
Terraform以外からも状態を確認するため、Google Cloud CLIで有効なAPIを取得します。
gcloud services list --enabled \
--project="$(terraform output -raw project_id)" \
--filter='config.name:(compute.googleapis.com OR iam.googleapis.com OR storage.googleapis.com)'
次の3つが表示されれば、Service Usage 上で対象APIが有効として登録されています。直ちに利用できることまでは保証しません。 上に書いた結果整合性のためです。
NAME
compute.googleapis.com
iam.googleapis.com
storage.googleapis.com
エラー・注意点 #
Service Usageの権限がない #
APIを有効化するアカウントにserviceusage.services.enable権限がない場合、権限エラーになります。
Service Usage Admin(roles/serviceusage.serviceUsageAdmin)など、必要な権限を含むロールが対象Projectで付与されているか確認します。
Service Usage APIが無効になっている #
APIを管理するためのService Usage API自体が無効な場合は、先に有効化します。
gcloud services enable serviceusage.googleapis.com \
--project=YOUR_PROJECT_ID
APIの有効化自体では通常課金されない #
APIを有効化しただけでは、通常は追加料金は発生しません。ただし、有効化したAPIを使ってVMやデータなどの課金対象リソースを作成すると料金が発生します。
APIを無効化しても、保存済みデータが自動的に削除されるとは限りません。Cloud StorageやBigQueryなどにデータが残っている場合、APIの無効化後も保存料金が発生する可能性があります。
後片付け #
Terraformの管理対象からAPI設定を削除します。
terraform destroy
このサンプルではdisable_on_destroy = falseがデフォルトなので、destroy後もAPIは有効なまま残り、Terraform Stateから管理対象が削除されます。
以下の表は仕様の整理です。 true側は実行していません。
disable_on_destroy |
destroy後の動作 |
|---|---|
false |
APIを有効なまま残し、Terraformの管理対象から外す |
true |
Terraform Resourceの削除時にAPIを無効化する |
既存Projectや複数のシステムが利用するProjectでは、他のリソースに影響しないようfalseのままにする方が安全です。
disable_on_destroy = trueの場合、対象APIへ依存する有効なAPIが存在すると、無効化処理はエラーになります。disable_dependent_services = trueを設定すると依存APIも無効化できますが、影響範囲が広がるため慎重に使用します。
まとめ #
google_project_serviceでGoogle Cloud APIを有効化できるfor_eachを使って複数のAPIをService名単位で管理できる- Terraform Outputと
gcloud services listの両方で結果を確認できる disable_on_destroy = falseならdestroy後もAPIを有効なまま残せる- APIと保存データの削除は別の操作として考える必要がある
参考資料 #
- Terraform Google Provider: google_project_service
- Terraform Google Provider: User guide for google_project_service
- Google Cloud: サービスの有効化と無効化
- Google Cloud: Service Usageのアクセス制御
次回 #
次は、Terraformで専用VPC、Subnet、Firewall Ruleを作成し、Google Cloudの基本的なネットワーク構成を確認します。