😎

Terraform Google Provider 5.0.0 の新機能と変更点について

2023/10/05に公開

こんにちは。クラウドエースの阿部です。
この記事ではメジャーアップデートした Terraform Google Provider 5.0.0 の新機能と変更点について説明しようと思います。

概要

2023年10月3日に、Terraform の Google Cloud 向けプラグイン(Provider)である Terraform Google Provider が 5.0.0 にバージョンアップしました。
v4.0.0 のリリースは 2021年11月3日だったため、Provider のメジャーアップグレードは約2年ぶりということになります。
ざっとリリース情報やアップグレードガイドを読むと、変更点が多かったので筆者が気になった点についてまとめていきたいと思います。

対象読者

  • Terraform で Google Cloud の構築・運用をしているエンジニア
  • メジャーバージョン間の非互換が気になる方

変更点概要

5.0.0 になったことで、バージョン 4 系から以下の点が変更されています。
主な変更点を以下に列挙します。

  • 新機能: Provider で設定したデフォルト値が terraform plan に表示されるようになった
  • 新機能: Provider でリソースラベルのデフォルト値(default_labels)を設定できるようになった
  • 新機能: ラベル設定可能なリソースで terraform_labels, effective_labels フィールドが追加された
  • 新機能: ラベル参照可能なデータリソースで labels, terraform_labels, effective_labels が追加された
  • 新機能: アノテーション設定可能なリソースで effective_annotations フィールドが追加された
  • 新機能: アノテーション参照可能なデータリソースで annotations, effective_annotations が追加された
  • 変更: リソースラベルフィールドが authoritative ではなく non-authoritative な動作に変更された
  • 変更: アノテーションフィールドが authoritative ではなく non-authoritative な動作に変更された
  • 非互換: Provider 設定において credentials, access_token, impersonate_service_account, project, billing_project, region, zone に空文字列が設定できないよう検証する動作が追加された
  • 非互換: terraform import に指定するリソースIDの検証が強化された
  • 非互換: データリソースで参照先リソースがない場合、404エラーで失敗する動作に変更された

また、上記以外にも多数のリソースにおいて機能追加、非互換、および、機能削除があります。
詳細は後述の参考リンクから、変更点を確認してください。

バージョン 4.x 系からアップグレードする場合の注意点

公式の 5.0.0 Upgrade Guide は原則 4.x 系の最終バージョンからのアップグレードについて説明しているドキュメントです。
そのため、推奨のアップグレード手順としては、まず現在の 4.x 系最終バージョンである 4.84.0 にアップグレードし、 terraform plan で意図しない差分が発生しないことを確認してから 5.0.0 にアップグレードすることをおすすめします。(4.x 系の Provider をお使いであれば、おそらく直接 5.0.0 にアップグレードしてもそこまで深刻な事態にはならないと思いますが、その場合 4.x のマイナーバージョン間の差分も合わせて考慮した上で作業する必要があります。)

バージョン 5.0.0 から 4.x 系にダウングレード可能かについて

いくつかの条件や作業状態において、ダウングレード可能な手段があります。

  1. Provider のバージョンを固定しておらず、 terraform init 等で最新の Provider をダウンロードしただけの場合、もしくは terraform plan を実行しただけの場合
    この場合は、 State ファイルは更新されていないはずなので、 Provider バージョンを固定する設定を追加してから改めて terraform init -upgrade を実行してください。
  2. terraform applyterraform refresh といった State ファイルを更新した場合
    1. ローカルステート等、 State ファイルのバージョニングの仕組みがない場合は前述の Provider ダウングレードを行った後、 terraform refresh を実行して State ファイルだけ更新すると復旧できる可能性があります。
    2. GCS バックエンドのリモートステートのように、 State ファイルのバックアップがある場合は、ファイルを更新前の状態に戻してから前述の Provider ダウングレードを実行することで元に戻すことが可能です。

ただ、アップグレードしてから新リソース追加等をしてしまい、State ファイルの状態が進んでいると、戻したときに作成したはずのリソースが未管理扱いになったりします。
ダウングレードはあくまで State の状態が進んでいない前提ですので、普段の運用でも Provider のバージョンを固定する設定は必要だと思います。

参考リンク

新機能

Provider で設定したデフォルト値が terraform plan で表示されるようになった

Provider ブロックには、これまで project,region,zone の3つのデフォルト値を設定できました。例えば、以下のような Provider ブロック設定があるとします。

provider "google" {
  project = "example-project"
  region  = "asia-northeast1"
  zone    = "asia-northeast1-b"
}

この設定を使ってリソース設定すると、固定値であるにも関わらず terraform plan 時は (known after apply) という表示でした。以下は、Compute Engine インスタンス作成の plan ログの一部です。

4.84.0までのplan
  # google_compute_instance.main will be created
  + resource "google_compute_instance" "main" {
    ...(snip)...
      + name                 = "provider-test"
      + project              = (known after apply)
      + zone                 = (known after apply)
    ...(snip)...
    }

これだと、 plan の結果をレビューに使っているとき、設定値の確からしさを plan から確認できないという問題があります。

これが、 5.0.0 から以下のようになります。Provider ブロックに設定した projectzone のデフォルト値が plan 実行時に表示されるようになりました。

5.0.0のplan
  # google_compute_instance.main will be created
  + resource "google_compute_instance" "main" {
    ...(snip)...
      + name                 = "provider-test"
      + project              = "example-project"
      + zone                 = "asia-northeast1-b"
    ...(snip)...
    }

これまでは plan 時に設定値を確認できないことから、私はプロジェクトメンバーに Provider のデフォルト値を極力使わないよう指示していましたが、 5.0.0 のように表示されるなら忌避しなくてもよいかと考えています。

Provider でリソースラベルのデフォルト値(default_labels)を設定できるようになった

Provider でリソースラベルのデフォルト値を設定できるようになりました。
以下のように設定します。

provider "google" {
  project = "example-project"
  region  = "asia-northeast1"
  zone    = "asia-northeast1-b"
  default_labels = {
    tool = "terraform"
  }
}

こうすることで、上記 Provider で作成するラベル設定が可能な全てのリソースに、 key が tool 、 value が terraform のラベルを追加することが可能です。
使いどころとしては、Cloud コンソールや gcloud コマンドで Terraform で作成したリソースかそうでないかを確認するときに便利だと思います。
また、コスト管理等でリソースに漏れなくラベルを設定したい際に、これまではマメにラベルがコーディングされているかをレビューしたり、テストツールでチェックするといったことが必要でしたが、 Provider レベルでデフォルトラベルが設定できれば少なくともコーディングのレビューの負担は減ると思います。

ラベル設定可能なリソースで terraform_labels, effective_labels フィールドが追加された

5.0.0 から、 terraform_labels, effective_labels という参照のみ(output-only)のフィールドが追加されました。
このフィールドは、前述の Provider で記述したデフォルトラベル設定と、リソース毎に記述するラベル設定、そして Terraform で設定していない現物リソースに存在するラベルの3つをそれぞれマージしたものになります。

  • terraform_labels は、Provider デフォルトラベルとリソース毎のラベル設定をマージした設定を表示します。
  • effective_labels は、前述の terraform_labels に加え既に現物リソースに設定されている内容も含めた最終的な設定内容を表示します。

これにより、ラベルを別のツールで一括設定した際に Terraform も追従する必要がなく、ラベル設定は Terraform のコードだけ気にすれば良くなっています。

ラベル参照可能なデータリソースで labels, terraform_labels, effective_labels が追加された

これはそのままですね。 Data Resource (data ブロック)で参照するときに、ラベルフィールドも参照できるようになりました。

アノテーション設定可能なリソースで effective_annotations フィールドが追加された

アノテーション(annotations)が設定可能なリソース(例えば Cloud Run サービスリソース)に、 effective_annotations フィールドが追加されました。
このフィールドは、「ラベル設定可能なリソースで terraform_labels, effective_labels フィールドが追加された」で説明した effective_labels の動作に似ています。

4.84.0 以前の動作として、 annotations フィールドは authoritative であり、Terraform で設定された値を正として完全に置き換える動作でした。
Cloud Run サービスを例に挙げると、Terraform 管理下の Cloud Run サービスに、 Cloud コンソールや gcloud コマンド等で更新すると、これらのツールを使用したときに暗黙で設定されるアノテーション(例えば、run.googleapis.com/client-name)があるため、 Terraform 実行時に意図しない差分が発生することがありました。
5.0.0 では、実際に設定されている値と Terraform で設定する値をマージした effective_annotations を計算してから適用するため、意図しない差分の発生がなくなります。

アノテーション参照可能なデータリソースで annotations, effective_annotations が追加された

Data Resource (data ブロック)で参照するときに、アノテーションフィールド(annotations, effective_annotations)も参照できるようになりました。

変更点

リソースラベルフィールドが authoritative ではなく non-authoritative な動作に変更された

新機能の「ラベル設定可能なリソースで terraform_labels, effective_labels フィールドが追加された」に関連しますが、ラベル設定が authoritative ではなく non-authoritative な動作に変更されました。
即ち、 Terraform 設定が現物リソースの設定を全て上書きする動作(authoritative)から、デフォルトラベル、リソースラベル、現物の設定済みラベル全てを加味した上で設定値をマージする動作(non-authoritative)になったということです。
これは、ラベル設定を Terraform 上で厳密に行いたい場合はデメリットですが、ほとんどのケースでは non-authoritative の方がメリットがあると判断され、変更になったと推測しています。(Provider デフォルトラベルとの兼ね合いもあると思います。)

この動作変更により、 terraform plan 等で意図しない差分が発生する可能性がありますので、公式ドキュメントの Provider-level Labels Rework に記載されている注意事項を確認しながら必要に応じてコード修正を行いましょう。

アノテーションフィールドが authoritative ではなく non-authoritative な動作に変更された

新機能の「アノテーション設定可能なリソースで effective_annotations フィールドが追加された」に関連しますが、アノテーション設定が authoritative ではなく non-authoritative な動作に変更されました。
これにより、Terraform 以外のツールで設定されたアノテーション設定を残したまま Terraform で設定できるようになりました。
この動作による副作用はあまりないと思いますが、これまで annotaions 設定で意図しない差分を抑止するために lifecycle.ignore_changes を設定している場合は、様子を見ながら外してもよいのではないかと思います。

非互換

Provider 設定において credentials, access_token, impersonate_service_account, project, billing_project, region, zone に空文字列が設定できないよう検証する動作が追加された

これは掲題の通りで、4.84.0 以前は空文字列も設定可能でした。(筆者は空文字列を設定したことがないので気付きませんでしたが……)
そのため、明らかに apply が失敗するような設定でも plan でも成功してしまうケースがありました。

5.0.0 では、 plan 実行時に以下のようなエラーメッセージを出力します。

Provider ブロック例
provider "google" {
  project = ""
}
エラー例
│ Error: expected a non-empty string
│
│   with provider["registry.terraform.io/hashicorp/google"],
│   on versions.tf line 11, in provider "google":
│   11: provider "google" {
│
│ project was set to ``
╵

terraform import に指定するリソースIDの検証が強化された

この動作変更は内部ロジックの正規表現で ^$ を追加し リソース ID 形式の文字列検証を少しだけ厳密化しただけです。
実際の修正はこちらの Pull Request が該当します。
実運用上はそこまで影響しないのではないかと思いますが、もし 5.0.0 で import するときにうまく実行できない場合は、リソース ID 文字列の形式を見直すとよいと思います。

データリソースで参照先リソースがない場合、404エラーで失敗する動作に変更した

Data Resource を使用する際に存在しないリソースを参照したとき、 4.84.0 以前は plan を実行してもエラーが発生しませんでした。
5.0.0 では、存在しないリソースを参照した場合、 以下のようなエラーが発生し plan に失敗します。( defaulte という存在しない VPC ネットワークを参照したときの例です。)

エラー例
Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: projects/example-project/global/networks/defaulte not found
│
│   with data.google_compute_network.default,
│   on data.tf line 1, in data "google_compute_network" "default":
│    1: data "google_compute_network" "default" {
│
╵

リソース単位での機能変更や廃止について

メジャーバージョンアップしたことで、これまで破壊的な変更として保留されていたリソース毎の変更や廃止がまとめて行われています。
この記事で全てを紹介しませんが、筆者が気になったところについてピックアップして紹介します。
変更点の全量を確認したい場合は、5.0.0 リリース情報5.0.0 Upgrade Guide を確認してください。

Game Servers リソースと Cloud IoT リソースを廃止

Google Cloud で廃止された Game Servers と Cloud IoT ですが、 5.0.0 で Provider としても廃止されました。
具体的には以下のリソースです。

Game Servers リソース

  • google_game_services_game_server_cluster
  • google_game_services_game_server_deployment
  • google_game_services_game_server_config
  • google_game_services_realm
  • google_game_services_game_server_deployment_rollout

Cloud IoT リソース

  • google_cloudiot_device
  • google_cloudiot_registry
  • google_cloudiot_registry_iam_*
  • data.google_cloudiot_registry_iam_policy

Access Context Manager リソースの設定順序や重複設定時の動作を改善

google_access_context_manager_service_perimetersgoogle_access_context_manager_service_perimeter において、 Terraform 上の設定順序と実リソースの設定の順序が変わった際に意図しない差分が発生することがありましたが、この動作が改善されています。
また、 内部動作を変更したことにより、重複設定があった場合に plan 時点で検出できるようになりました。

GKE クラスタリソースがデフォルトで削除不可に設定

google_container_cluster リソースはデフォルトで deletion_protection フィールドに true を設定するようになりました。
そのため、誤って削除する動作を防ぐことができます。
Terraform で GKE クラスタを削除したい場合、 deletion_protection フィールドに false を明示的に設定し、apply してからリソースのコードを削除する操作が必要です。

作成に中途半端に失敗した GKE クラスタの扱いを変更

google_container_cluster リソースで作成した GKE クラスタが、何らかの理由で Healthy にならずリソース作成が中途半端に失敗することがありました。
4.84.0 以前は State ファイルから除外され、再度 apply したとき新規作成状態になりますが、 5.0.0 では State ファイルに taint 状態で記録されます。
そのため、 GKE クラスタ側を直接修復して復旧した場合、 apply せず taint 状態を解除するといった操作が必要です。

GKE クラスタのデフォルトを VPC ネイティブクラスタに変更

5.0.0google_container_cluster リソースで作成した GKE クラスタは VPC ネイティブクラスタがデフォルトになります。
4.84.0 以前は、 ip_allocation_policy ブロックが設定されていない限り、 ルートベースクラスタで作成していました。

GKE ノードプールの自動アップグレードと自動復旧がデフォルト有効に変更

google_container_node_pool リソースの management.auto_repairmanagement.auto_upgrade がデフォルトで true に設定されます。
これまで未設定の場合は差分が発生する可能性があります。

Cloud Logging Sink のユニーク書き込み ID がデフォルトで有効に変更

google_logging_project_sink リソースの unique_writer_identity がデフォルトで true に設定されます。
これにより、 unique_writer_identity フィールド未設定の場合は差分が発生する可能性があります。
unique_writer_identity フィールドの設定値によって、 アクセス許可設定するべきサービスアカウントも変更されますので、これまでの動作を変更したくない場合は明示的な設定が必要です。

Cloud Monitoring Dashboard の差分検出が改善

4.84.0 以前は、 google_monitoring_dashboard リソースの dashboard_json フィールドに設定する値は、厳密に一致していないと差分が多く出るためメンテナンスが非常に煩雑でした。
5.0.0 では、dashboard_json フィールドのパラメータで明示的に設定していないが、ダッシュボード API でデフォルト値を生成する場合等については差分を抑制する処理に変更されています。

Secret Manager リソースの複製における automatic フィールドを auto ブロックに置き換え

google_secret_manager_secret リソースの automatic フィールドが廃止され、代わりに auto ブロックで設定します。
設定のサンプルはこちらのドキュメントをご確認ください。

Cloud SQL データベースのデータベースフラグが順序性を持たないように変更

google_sql_database リソースの database_flags は順序性を持たない内部処理に変更されました。
そのため、意図しない差分が発生しづらくなっています。

まとめ

バージョン 5.0.0 になってより成熟度が高くなった Google Provider の変更点について紹介しました。
リソースラベルのデフォルト設定等、機会があれば活用したい機能追加もありますので、引き続き Google Provider の更新をウォッチしていこうと思います。
この記事が皆様の Google Provider アップグレード作業の一助になれば幸いです。

Discussion