
Terraform 連載2024の3本目です。
はじめに
はじめまして。フューチャーキャリア入社1年半の森と申します。
Terraformにおける変数を、構築するインフラの要件に合わせてどのように制御していくかについてまとめます。
Terraformにおける変数制御は、構築するインフラの要件を明確化させる上で重要です。そのため、どのような変数制御があるか、ユースケースを踏まえ見ていきます。
Terraformの変数制御
Terraformには型による制約の他に、下記3種類の変数の制御方法があります。
- validation : 変数の静的な事前チェックを実施する
- precondition(v1.2以降) : 変数の動的な事前チェックを実施する
- postcondition(v1.2以降) : 変数の動的な事後チェックを実施する
静的・動的の可不可や、事前・事後のチェックなどの違いがありますが、図にするとこのような感じです。
動的チェック | 事前チェック | 事後チェック | |
---|---|---|---|
validation | 不可 | 可 | 不可 |
precondition | 可 | 可 | 不可 |
postcondition | 可 | 不可 | 可 |
具体的に1つずつ確認していきましょう。
validationについて
validation
は3つの変数制御の中でも最もシンプルで簡単な制御の方法です
例えば、AWSのEC2でEBSを暗号化したい場合、以下のようにvalidation
ブロックを暗号化の有無に関する変数に追加します。
このブロックのcondition
の内容で真偽を判定し、偽の場合error_message
で指定のエラーメッセージを出力できます。
resource "aws_instance" "example" { ami = "ami-020283e959651b381" instance_type = "t2.micro" subnet_id = "subnet-xxxxxxx" ebs_block_device { device_name = "/dev/sdh" encrypted = var.ebs_encryption } } variable "ebs_encryption" { type = bool validation { condition = var.ebs_encryption == true error_message = "EBS Should Be Encrypted" } description = "A Boolean of EBS Encryption in the EC2 Instances" } |
ebs_encryption
にfalse
を指定した場合、terraform plan
時にvalidation
ブロックで指定した下記のエラーメッセージが出されます。
╷ |
このようにcondition
に条件式を書いておくことで、誤ってEBSの暗号化を無効にする事のないように事前にチェックをしてくれるのがvalidation
の特徴です。
validationのユースケース
構築したいインフラに対して、あらかじめ変数の条件をハードコードすることで制約を課したい場合にvalidation
ブロックが使えます。
preconditionについて
上述のvalidation
で課すことのできる制約は静的な条件に限りました。つまり、全て条件式にハードコードして制御する必要があり、動的にAWSから情報を取得して条件を絞ることは不可能でした。
これを解決したのがTerraform v1.2から追加されたprecondition
です。例えば、EC2のインスタンスタイプを無料利用枠のみに制限したい場合、aws_ec2_instance_type
データソースから最新の無料利用枠の情報をAWSから取得し、インスタンス構築の際の条件に課すことが可能です。
lifecycle
ブロック内にprecondition
ブロックを作成し、condition
の条件で真偽を判定し、偽の場合にerror_message
に記載されているメッセージを出力できます。
data "aws_ec2_instance_type" "example" { instance_type = "c5.xlarge" } resource "aws_instance" "example" { ami = "ami-0f7b55661ecbbe44c" instance_type = data.aws_ec2_instance_type.example.instance_type subnet_id = "subnet-xxxxxxxxxx" lifecycle { precondition { condition = data.aws_ec2_instance_type.example.free_tier_eligible error_message = "This instance type is not free in AWS" } } } |
上記のようにインスタンスタイプをc5.xlarge
(無料利用枠でないインスタンスタイプ)でplanを流してみるとどうなるでしょうか?
╷ |
指定のエラーメッセージとともに無事? planが通らなくなりました。(当然、applyもできません。)
このようにvalidation
と違って動的な変数の制御を可能にするのがprecondition
の特徴です。
preconditionのユースケース
validation
でハードコーディングするのが難しい場合に使うのが良いでしょう。
最新のAWSからの情報が常に反映されるため、より安定的なチェックが実施できます。
postconditionについて
varidation
やprecondition
はapply前に変数をチェックする事前チェックでした。一方でpostcondition
は、applyの後にエラーを追跡する事後チェックが可能です。
例としてオートスケーリンググループを作成する際、AZが2つ以上あるかどうかをチェックしたい場合を考えます。書き方はprecondition
と同様で、postcondition
ブロックのcondition
でAZの数が1よりも大きくない場合に指定のエラーメッセージを出力するようにします。
resource "aws_launch_configuration" "example" { image_id = "ami-020283e959651b381" instance_type = "t2.micro" } resource "aws_autoscaling_group" "example" { name = "ASG" launch_configuration = aws_launch_configuration.example.name vpc_zone_identifier = ["subnet-xxxxxxx"] min_size = 1 max_size = 1 lifecycle { postcondition { condition = length(self.availability_zones) > 1 error_message = "You need to choose more than 1 AZ to ensure high availability" } } } |
planをしてみましょう。この時点でAZはknown after apply
とあるので、エラーは捕捉されずにplan自体は通ります。
Terraform will perform the following actions: |
この状態でapplyすると完了後に下記のエラーが出ます。
╷ |
エラーは出力されていますが、precondition
と異なり、planはちゃんと通ってリソースまで作成されているのが分かります。
これがpostcondition
の事後チェックというもので、apply後へのリソースの変数に対するチェックを実施することが可能になっています。
postconditionのユースケース
validation
やprecondition
などの事前チェックのみで補足しきれない条件を課すのが良いでしょう。
上記のような例だと、apply時にリソースが作成されてしまうので、事前チェックのようにリソース作成前に制限を課すような強い制約ができないことには注意が必要です。
おまけ
インスタンスタイプの選定でprecondition
を使いましたが、precondition
→postcondition
と単純に置き換えてみたらどうなるでしょうか?
data "aws_ec2_instance_type" "example" { instance_type = "c5.xlarge" } resource "aws_instance" "example" { ami = "ami-0f7b55661ecbbe44c" instance_type = data.aws_ec2_instance_type.example.instance_type subnet_id = "subnet-xxxxxxx" lifecycle { postcondition { condition = data.aws_ec2_instance_type.example.free_tier_eligible error_message = "This instance type is not free in AWS" } } } |
上記はpreconditionについてにおけるコードでprecondition
がpostcondition
に置き換わっているだけです。
planで下記エラーが出てきます。
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: |
エラーメッセージはprecondition
とほぼ変わらないのですが、postcondition
では plan によるリソース出力が成功します(precondition
ではplanが失敗してリソース出力がされませんでした)。
これはpostcondition
が事後チェックであることを反映している例で、データソースやリソースが取得された後で値が評価されていることを如実に表しています。
こうなると postcondition
で全部チェックしてしまっても良い気もしますが、事後チェックであるかを明示するため、precondition
で制御できる箇所はprecondition
で制御するようにしましょう。
さいごに
多くの変数に対して制限を課すのはなかなか大変で工数を取る上、可読性にも影響します。
修正の際にupdate in placeなどで気軽にアップデート出来ない変数(EBS暗号化の有無など)に対する制約から優先的に実施するのが個人的には良いと思います。