こんにちは。X(クロス)イノベーション本部クラウドイノベーションセンターの柴田です。
この記事は 電通国際情報サービス Advent Calendar 2023 の5日目の投稿です。
前日の記事は宮澤さんの「Jira Automationで作成した変数のスコープについて」でした。
はじめに
Terraformでインフラストラクチャを構築する際、変数やリソースが期待する条件を満たしているか検証したいケースがあると思います。
この記事では変数やオブジェクトの検証に役立つTerraformの以下の機能を紹介します。
- 入力変数の検証
- オブジェクトの事前条件と事後条件の検証
- 構築したインフラストラクチャの
check
による検証
なお、この記事の内容は以下のバージョンのTerraformを前提とします。
$ terraform version Terraform v1.6.3 on linux_amd64
入力変数の検証
概要
入力変数の値が指定した条件を満たしているか validation
を用いて検証します。
この機能はTerraform v0.13.0以降で利用できます。
設定方法
variable
に1つ以上の validation
を設定します。
中身は以下の表のとおりです。
入力変数の検証の場合 condition
が参照できる変数は自身のみです。
項目 | 説明 |
---|---|
condition |
満たすべき条件。 true なら検証成功、 false なら検証失敗。 |
error_message |
検証に失敗した場合に表示されるエラーメッセージ。 |
variable "image_id" { type = string description = "The id of the machine image (AMI) to use for the server." validation { condition = can(regex("^ami-", var.image_id)) error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"." } }
検証
planとapplyの実行時に各 variable
の condition
が評価されます。
condition
が false
になるとTerraformは error_message
を含むエラーを表示して異常終了します。
$ terraform plan -var image_id=123 Planning failed. Terraform encountered an error while generating this plan. ╷ │ Error: Invalid value for variable │ │ on variables.tf line 1: │ 1: variable "image_id" { │ ├──────────────── │ │ var.image_id is "123" │ │ The image_id value must be a valid AMI id, starting with "ami-". │ │ This was checked by the validation rule at variables.tf:5,3-13. ╵
オブジェクトの事前条件と事後条件の検証
概要
各オブジェクトを評価する前後に、指定した条件を満たしているかを検証します。
事前条件は precondition
、事後条件は postcondition
を使用します。
この機能はTerraform v1.2.0以降で利用できます。
ユースケース
事前条件には特定のオブジェクトを評価するために満たすべき前提条件を記述します。
事後条件には特定のオブジェクトが評価後に保証すべき条件を記述します。
設定方法
以下のオブジェクトに事前条件と事後条件を設定できます。
- リソース(
resource
) - データソース(
data
) - 出力(
output
) ※事前条件のみ利用可能
リソース、データソース
resource
または data
の lifecycle
に事前条件 precondition
または事後条件 postcondition
を設定します。
それぞれ中身は先ほどと同じです。
入力変数の検証と異なり condition
は他のオブジェクトを参照できます。
resource "aws_instance" "example" { instance_type = "t3.micro" ami = data.aws_ami.example.id lifecycle { precondition { condition = data.aws_ami.example.architecture == "x86_64" error_message = "The selected AMI must be for the x86_64 architecture." } postcondition { condition = self.public_dns != "" error_message = "EC2 instance must be in a VPC that has public DNS hostnames enabled." } } }
上の例ではリソース aws_instance.example
に対して以下の条件を設定しています。
self
は評価中のオブジェクト自身を参照するオブジェクトです。事後条件でのみ利用できます。
事前条件と事後条件は count
や for_each
と併用できます。
出力
output
に事前条件 precondition
を設定します。
事後条件 postcondition
は設定できません。
中身は先ほどと同じです。
output "ami_id" { value = data.aws_ami.example.id precondition { condition = data.aws_ami.example.architecture == "x86_64" error_message = "The selected AMI must be for the x86_64 architecture." } }
検証
planとapplyの実行時に各オブジェクトの事前条件 precondition
と事後条件 postcondition
の condition
が評価されます。
各オブジェクトの検証のライフサイクルは以下のとおりです。
- 事前条件の検証
- オブジェクトの評価
- 事後条件の検証
事後条件は「apply後に評価される条件」ではなく「オブジェクトの評価後に評価される条件」です。
そのためplanの実行時にも事後条件は評価されます。
condition
に未確定の値が含まれる場合、その condition
の評価は値が確定するまで保留されます。
特に known after apply
な値を含む condition
はplanの実行時には評価されません。
condition
が false
になると、以降の処理は中断され、Terraformは error_message
を含むエラーを表示して異常終了します。
ただし作成済みのリソースは削除されません。
$ terraform plan data.aws_ami.example: Reading... data.aws_ami.example: Read complete after 0s [id=ami-0d8d9f072b1e8e8fe] Planning failed. Terraform encountered an error while generating this plan. ╷ │ Error: Resource precondition failed │ │ on condition.tf line 17, in resource "aws_instance" "example": │ 17: condition = data.aws_ami.example.architecture == "x86_64" │ ├──────────────── │ │ data.aws_ami.example.architecture is "arm64" │ │ The selected AMI must be for the x86_64 architecture. ╵
構築したインフラストラクチャの check
による検証
概要
planとapplyの実行の終わりに指定した条件が満たされているか check
を用いて検証します。
check
の検証は、これまで説明した他の検証機能と異なり、検証に失敗してもplanやapplyの実行は中断されません。
この機能はTerraform v1.5.0以降で利用できます。
ユースケース
構築したインフラストラクチャが指定した条件を満たしているか検証します。
check
は事後条件と似ていますが
- 特定のオブジェクトではなくインフラストラクチャ全体を検証したい場合
- 検証に失敗した際にエラーを発生させて処理を中断したくない場合
には事後条件よりも check
を使うとよいでしょう。
設定方法
- 0〜1個のデータソース
- 1個以上の
assert
を含む check
を設定します。
check
内のデータソースはスコープ付きデータソースと呼ばれ、以下の特徴があります。
check
の外側からは参照できません。for_each
やcount
との併用はできません。
assert
の中身は先ほどと同じです。
check "health_check" { data "http" "alb" { url = "https://${aws_lb.example.dns_name}" } assert { condition = data.http.alb.status_code == 200 error_message = "${data.http.alb.url} returned an unhealthy status code" } }
検証
planとapplyの実行の終わりに condition
が評価されます。
事前条件や事後条件と同じく known after apply
な値に依存する condition
はplanの実行時には評価されません。
インフラストラクチャがまだ構築されていないplan時に check
を評価したくない場合は、リソースが実際に作成された後にスコープ付きデータソースおよび condition
が評価されるよう、スコープ付きデータソースからリソースへの依存関係を depends_on
などを使って設定するとよいでしょう。
condition
が false
になった場合、またはスコープ付きデータソースのproviderでエラーが発生した場合、Terraformは error_message
を含む警告を表示して処理を継続します。
$ terraform plan # (中略) ╷ │ Warning: Error making request │ │ with data.http.alb, │ on main.tf line 14, in check "health_check": │ 14: data "http" "alb" { │ │ Error making request: GET https://example.com.invalid giving up after 1 attempt(s): Get "https://example.com.invalid": dial tcp: lookup example.com.invalid on 127.0.0.53:53: no such host ╵
まとめ
以下の表はここまでの内容をまとめたものです。
主なユースケース | 記述箇所 | 検証されるタイミング | count , for_each の併用 |
condition が false になった場合の挙動 |
|
---|---|---|---|---|---|
入力変数の検証 | 入力変数の検証 | variable |
variable の評価前 |
不可 | 異常終了 |
オブジェクトの事前条件の検証 | 特定のオブジェクトを評価するために満たすべき前提条件の検証 | resource , data , output |
各オブジェクトの評価前 | 可 | 異常終了。作成済みのリソースは削除されない。 |
オブジェクトの事後条件の検証 | 特定のオブジェクトが評価後に保証すべき条件の検証 | resource , data |
各オブジェクトの評価後 | 可 | 異常終了。作成済みのリソースは削除されない。 |
構築したインフラストラクチャの check による検証 |
構築したインフラストラクチャの検証 | check (スコープ付きデータソースを利用) |
planとapplyの終わり | 不可 | 警告を表示して処理を継続する |
おわりに
この記事ではTerraformの変数やオブジェクトが期待する条件を満たしているか検証する方法として以下の機能を紹介しました。
- 入力変数の検証
- オブジェクトの事前条件と事後条件の検証
- 構築したインフラストラクチャの
check
による検証
他にもTerraform v1.6で Tests の機能が導入されるなど、最近はTerraformの検証・テストに関する機能がどんどん充実していると感じます。
これらの機能を活用してより安全にインフラストラクチャを構築したいですね。
ここまで読んでいただきありがとうございました。
参考
- Custom Conditions - Configuration Language | Terraform | HashiCorp Developer
- Checks - Configuration Language | Terraform | HashiCorp Developer
私たちは一緒に働いてくれる仲間を募集しています!
クラウドアーキテクト執筆:@shibata.takao、レビュー:@fukutake.hiroaki
(Shodoで執筆されました)