Terraform 1.7.0 のリリースを読んでみた (1.7.1 もあるよ)
こんにちは、クラウドエース SRE 部の阿部です。
この記事では、2024 年 1 月 17 日にリリースされた Terraform 1.7.0 の変更点についてざっくり説明します。
また、1 月 24 日に Terraform 1.7.1 がリリースされておりますので、合わせて紹介します。
概要
2024 年 1 月 17 日にリリースされた Terraform 1.7.0 がリリースされました。
Terraform 1.6.6 から以下のような変更がありました。
v1.6.6 からの主な変更点
- Terraform 1.3 から実装された Check ブロックを実装しているときに、
terraform_remote_state
を使って State を参照するとエラーになる問題を修正- Terraform 1.7.0 だけでなく、 Terraform 1.3.10 、Terraform 1.4.7 、Terraform 1.5.7 でも修正されています。Terraform 1.6 系は影響がないため対象外です。
-
nonsensitive
関数で sensitive 属性がない値を設定した際にエラー扱いしていた動作を、エラー扱いしないよう変更 -
terraform graph
で表示される依存関係の対象をリソースのみにするよう変更 -
terraform test
で削除されるリソースの順序を run ブロックの逆順として単純化 -
terraform test
でモックを使ったテストを実装 (mock_provider
,override_resource
,override_data
,override_module
を追加) -
removed
ブロックを追加 -
import
ブロックでfor_each
引数を追加
上記以外にも、細かな機能追加やバグ修正があります。詳しくは Terraform 1.7.0 のリリースノートを参照してください。
v1.7.0 から v1.7.1 の修正点
基本的にはバグフィックスのみです。
-
terraform test
でvariables
ブロックの変数や関数を参照した際にクラッシュする問題を修正 -
terraform test
でoverride_module
ブロックにoutputs
属性が不足している場合にクラッシュする問題を修正
詳細は Terraform 1.7.1 のリリースノートを参照してください。
個人的な注目機能
個人的に注目したい以下の新機能や機能追加について、解説したいと思います。
-
terraform graph
の仕様変更 -
terraform test
のモック機能 -
removed
ブロック -
import
ブロックのfor_each
引数
また、この記事では解説はしませんが terraform_remote_state
を使っている方は、動作が改善されている各マイナーバージョンの最新にアップデートしておくことをおすすめします。
terraform graph の仕様変更
terraform graph
の表示が非常にシンプルになりました。 v1.6.6 以前は Root Module から始まり、 Terraform 内部の依存関係グラフをほぼそのまま表示しているような状態で、Terraform 自体の動作のデバッグには役立つものの、何かの資料で流用できるようなものではありませんでした。
v1.7.0 以降では、リソースのみに限定して、極めて分かりやすい出力に変更されています。以下は、同じソースコードから v1.6.6 と v1.7.1 で terraform graph
の出力した依存関係グラフを示します。また、参考までに Pluralith での出力結果も示します。※どれくらいグラフがシンプルになったかを見て頂きたいだけなので、ソースコードは省略します。
Terraform 1.6.6 の terraform graph
Terraform 1.7.1 の terraform graph
Pluralith の出力結果
こうして比較してみると、一目瞭然ですね。さらに言うと、 Pluralith はモジュールを考慮しませんが、 Terraform 1.7 ではモジュールとリソースの包含関係も考慮して出力します。
グラフの出力結果に、リソースの一部属性(例えば、 name
や zone
といったもの)も合わせて出力できると、詳細設計書等に添付してもよいくらいの情報量になりそうです。
terraform test のモック機能
terraform test
の大きな追加として、モックが使えるようになりました。
terraform test
は plan
モードと apply
モードの 2 種類があり、 plan
の情報でテストするか、実際に apply
して適用された結果を元にテストするか、という動作でした。
plan
モードは、主に読み取り系 API のみで検証するため現状のリソースには影響を与えませんが、リソース設定後に暗黙で他のパラメータも変更されるようなケースでは厳密なテストができません。
一方で apply
モードは実際にリソースを作成して検証するため、確実性の高いテストが実施できますが、実際にリソース作成するため時間もお金もかかります。さらに、テスト用リソースが既存のリソースと重複してしまう場合ではテストに失敗します。
モックを上手く使うことで、 apply
モード的なテストを疑似リソースで代行し、 plan
モードより確実性の高いテストが行える…… というものだと思います。
筆者が少し触ってみた感じでは、まだモックを使ったサンプルが少なく mock_provider
をはじめとする各ブロックでどのような設定を行うと、 plan
モードと apply
モードのいいとこどりができそうか、わかりませんでした。(一応、動いたな、くらいの感触)
モック機能を使いこなすにはもう少しキャッチアップが必要そうです。モック機能については今後様々な情報が出てくることも期待し、 Google Cloud 上でテストする上でよりよい使い方がわかれば記事にしていきたいです。
removed ブロック
removed
ブロックは、ソースコード上で削除設定を記述することで terraform state rm
を安全に実行できるというものです。
terraform state rm
の操作はそんなに難しくないですが、 システム運用の安全性を高めるために Remote State ファイルへのアクセスを制限しているケースがあると、おいそれと実行できません。
CI/CD のパイプライン上で安全に実行できればそれにこしたことはありませんので、なんらかの事情で Terraform 管理外にしたいリソースがあるが、 terraform state rm
実行はなるべくやりたくないといった場合に有用だと思います。
import ブロックの for_each
import
ブロックで for_each
メタ引数が使えるようになりました。
例えば、以下のようなソースコードがあったとします。
main.tf
locals {
instances = [
{
name = "test-alpha"
zone = "asia-northeast1-a"
},
{
name = "test-bravo"
zone = "asia-northeast1-b"
},
{
name = "test-charlie"
zone = "asia-northeast1-c"
}
]
}
resource "google_compute_instance" "test" {
for_each = { for v in local.instances : format("%s/%s", v["zone"], v["name"]) => v }
name = each.value["name"]
zone = each.value["zone"]
machine_type = "e2-medium"
boot_disk {
auto_delete = true
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
subnetwork = "default"
}
}
なお、このソースコードで boot_disk
ブロックで initialize_params
を記述している部分、および、 network_interface
に default
をリテラル文字列で記述している部分は、説明のため簡略化する目的であり、推奨するコーディング方法ではありません。
このソースコードで terraform apply
を実行すると、以下 3 つのインスタンスが起動します。
- test-alpha
- test-bravo
- test-charlie
このような for_each
を使ったソースコードで import
ブロックを記述する場合、 v1.6.6 以前は以下のような書き方になってしまいます。
main_import.tf (v1.6.6)
import {
to = google_compute_instance.test["asia-northeast1-a/test-alpha"]
id = format("%s/%s/%s", var.project_id, local.instances[0]["zone"], local.instances[0]["name"])
}
import {
to = google_compute_instance.test["asia-northeast1-b/test-bravo"]
id = format("%s/%s/%s", var.project_id, local.instances[1]["zone"], local.instances[1]["name"])
}
import {
to = google_compute_instance.test["asia-northeast1-c/test-charlie"]
id = format("%s/%s/%s", var.project_id, local.instances[2]["zone"], local.instances[2]["name"])
}
これは明らかにイケてないですね。私もそう思います。
さらに言えば、 v1.6.6 までは、 import
ブロックの to
引数には変数(local
やvariable
)が指定できません。
そのため、 for_each
で指定するリストやマップの要素数だけ import
ブロックを記述し、to
引数はリテラル文字列を使う必要がありました。
これが、v1.7.0 以降は以下のように記述できます。
main_import.tf (v1.7.0)
import {
for_each = { for v in local.instances : format("%s/%s", v["zone"], v["name"]) => v }
to = google_compute_instance.test[each.key]
id = format("%s/%s/%s", var.project_id, each.value["zone"], each.value["name"])
}
はい、最高です。 for_each
引数のおかげで 1 つのブロックに集約できました。
また、for_each
引数に指定する内容は main.tf
の google_compute_instance.test
と合わせるだけですので、一貫性もあります。
これから import
ブロックを使って既存リソースを Terraform 管理下に置くことを検討している方は、積極的に v1.7 以降を使用していきましょう。
まとめ
この記事では、 Terraform 1.7.0 で更新された機能について紹介しました。
IaC をする上で便利な機能が盛り込まれており、積極的にアップデートして実務でも使っていきたいところです。
この記事が、Terraform を利用する方のお役に立ちましたら幸いです。
Discussion