1. 概要
preconditionとpostconditionとは何かlifecycleブロック内での定義方法precondition(apply前チェック)の使い方postcondition(apply後チェック)の使い方checkブロックとの使い分け
preconditionはリソースの作成・更新前に、postconditionは作成・更新後に条件を検証します。条件が満たされない場合はapplyをエラーで中断します。
2. precondition / postcondition vs check ブロック
| 比較 | precondition/postcondition | checkブロック |
|---|---|---|
| 配置場所 | resource/dataのlifecycleブロック内 | トップレベル |
| 失敗時の挙動 | エラーでapplyを中断 | 警告のみ(続行) |
| 参照できる値 | 親リソース・dataの属性のみ | 独自dataを持てる |
| 用途 | 必須条件の強制 | 外部依存・状態確認 |
3. 基本構文
resource "リソース" "名前" {
# ...
lifecycle {
precondition {
condition = <apply前に検証する式>
error_message = "<エラーメッセージ>"
}
postcondition {
condition = <apply後に検証する式>
error_message = "<エラーメッセージ>"
}
}
}
4. precondition — apply前の条件チェック
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
variable "environment" {
description = "環境名(dev/stg/prd)"
type = string
default = "dev"
}
variable "instance_type" {
description = "EC2インスタンスタイプ"
type = string
default = "t3.micro"
}
data "aws_ami" "amazon_linux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = var.instance_type
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.environment}-web"
Environment = var.environment
ManagedBy = "terraform"
}
lifecycle {
# 本番環境では小さすぎるインスタンスタイプを禁止
precondition {
condition = !(var.environment == "prd" && var.instance_type == "t3.micro")
error_message = "本番環境ではt3.micro以上のインスタンスタイプを使用してください。現在: ${var.instance_type}"
}
}
}
5. postcondition — apply後の状態確認
selfキーワードで作成されたリソース自身の属性を参照できます。
resource "aws_instance" "app" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = var.instance_type
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.environment}-app"
Environment = var.environment
ManagedBy = "terraform"
}
lifecycle {
# apply後: インスタンスが実際に起動しているか確認
postcondition {
condition = self.instance_state == "running"
error_message = "インスタンスが起動状態ではありません。現在の状態: ${self.instance_state}"
}
}
}
6. outputブロックにpreconditionを使う
outputブロックにもpreconditionを設定できます。モジュールが外部に公開する値が要件を満たしているかを確認する用途に使います。
output "instance_public_ip" {
value = aws_instance.web.public_ip
precondition {
condition = aws_instance.web.public_ip != ""
error_message = "インスタンスにパブリックIPが割り当てられていません。VPC設定を確認してください。"
}
}
7. dataブロックにpreconditionを使う
dataブロックにもprecondition/postconditionを設定できます。
data "aws_vpc" "selected" {
filter {
name = "tag:Environment"
values = [var.environment]
}
lifecycle {
postcondition {
# 取得したVPCのCIDRが期待通りか確認
condition = self.cidr_block == "10.0.0.0/16"
error_message = "VPCのCIDRが期待値と異なります。取得値: ${self.cidr_block}"
}
}
}
8. 複数条件を組み合わせる
variable "volume_size" {
description = "EBSボリュームサイズ(GB)"
type = number
default = 20
}
resource "aws_instance" "db" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = var.instance_type
root_block_device {
volume_size = var.volume_size
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.environment}-db"
Environment = var.environment
ManagedBy = "terraform"
}
lifecycle {
precondition {
condition = var.volume_size >= 20
error_message = "EBSボリュームは最低20GB必要です。指定値: ${var.volume_size}GB"
}
precondition {
condition = contains(["dev", "stg", "prd"], var.environment)
error_message = "environmentはdev/stg/prdのいずれかを指定してください。"
}
}
}
9. 関連記事
- lifecycle の使い方 — create_before_destroy・prevent_destroy・ignore_changes
- check ブロック — 警告のみのインフラ検証
- variable(入力変数)の使い方 — validationブロックとの使い分け
- resourceブロック — 基本構文と使い方
- terraform test — テストの書き方(1.6+)
- 条件式(三項演算子)— 使い方
10. まとめ
preconditionはapply前の条件チェック、postconditionはapply後の確認- 条件が満たされない場合はapplyをエラーで中断する(
checkは警告のみ) lifecycleブロック内に複数設定できるpostconditionではselfで作成されたリソース自身の属性を参照できるdataブロックにも設定可能
動作確認バージョン: Terraform >= 1.2 公式ドキュメント: https://developer.hashicorp.com/terraform/language/expressions/custom-conditions