03. 値(variable / local / output)
Terraform の「値」には 3 つの場所 があります。variable は外から受け取る値、local は中で計算する値、output は外に返す値。役割をちゃんと分けると、コードがぐっと読みやすくなります。
3 種類の使い分け
| 役割 | 参照する書き方 | 使う場面 | |
|---|---|---|---|
| variable | 外から受け取る入力 | var.NAME | 環境ごとに変えたい値(リージョン、サイズ) |
| local | 内部で計算する中間値 | local.NAME | 長い式の名前付け、共通タグ |
| output | 外に出す結果 | (モジュールから親へ) | VPC ID を別モジュールに渡す等 |
variable(入力)
# 文字列の変数(必須項目ではない=default あり)
# 使う側は var.region でアクセス
variable "region" {
type = string
description = "AWS リージョン"
default = "ap-northeast-1"
}
# 文字列の変数(最小限の指定)
variable "instance_type" {
type = string
default = "t3.micro"
}
# list 型の変数(同じ型の要素を順序付きで複数持つ)
variable "subnet_cidrs" {
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
# map 型の変数(キーと値のペア。値はすべて同じ型)
variable "tags" {
type = map(string)
default = {
Project = "hcl-guide"
Env = "dev"
}
}
variable の主要属性
| 属性 | 意味 |
|---|---|
type | 受け付ける型(次章)。型を書くとミス値で弾かれる |
default | 省略時の値。書かないと「必須入力」 |
description | 説明。terraform plan やドキュメント生成で使われる |
sensitive | true で plan/apply 出力にマスク表示 |
nullable | false で null 不可(デフォルト true) |
validation | 値の妥当性チェック(後述) |
variable に値を渡す方法と優先順位
同じ変数に複数の経路から値が来ると、下に行くほど強い(後から上書き)。
- variable の
default(最弱) - 環境変数
TF_VAR_NAME terraform.tfvarsterraform.tfvars.json*.auto.tfvars/*.auto.tfvars.json(辞書順に)- CLI の
-var-file/-var(最強)
tfvars ファイルの書き方
# terraform.tfvars
region = "us-east-1"
instance_type = "t3.small"
subnet_cidrs = ["10.10.1.0/24", "10.10.2.0/24"]
# 環境ごとの tfvars を CLI で指定
terraform apply -var-file=envs/prd/terraform.tfvars
# ピンポイントで上書き
terraform apply -var="instance_type=t3.large"
# 環境変数で渡す(自動化で便利)
export TF_VAR_region=ap-northeast-1
terraform apply
validation で値を検証する
受け取った値が「想定外」で apply が走ってしまう前に、validation で止められます。
# validation ブロック: 値を受け取った直後にチェック
# condition が false なら error_message を表示して plan を中断
variable "environment" {
type = string
description = "環境名"
validation {
# contains(LIST, VALUE) で「LIST に VALUE が含まれているか」を判定
condition = contains(["dev", "stg", "prd"], var.environment)
error_message = "environment は dev / stg / prd のいずれかにしてください。"
}
}
# 複雑な検証は can() と組み合わせる
variable "vpc_cidr" {
type = string
validation {
# cidrnetmask() は無効な CIDR でエラーになる
# can() で「エラーにならず評価できるか」を真偽値に変換
condition = can(cidrnetmask(var.vpc_cidr))
error_message = "vpc_cidr は有効な CIDR でなければなりません(例: 10.0.0.0/16)。"
}
}
locals(内部計算)
locals は「式の結果に名前を付ける」場所。同じ式を 3 か所で使うなら local にまとめると変更が 1 か所で済みます。
# locals ブロック: 「式の結果に名前を付ける」場所
# 参照側は local.name_prefix のように local.XXX で書く(locals ではなく local)
locals {
# 文字列を組み合わせて命名プレフィックス。例: "myapp-prd"
name_prefix = "${var.project}-${var.environment}"
# 比較式の結果(true / false)を保存。後で if 的に使う
is_prod = var.environment == "prd"
# 共通タグを 1 か所で定義 → 複数リソースで使い回し
common_tags = {
Project = var.project
Env = var.environment
ManagedBy = "Terraform"
}
}
# local.name_prefix で参照 → "myapp-prd-logs" というバケット名になる
resource "aws_s3_bucket" "logs" {
bucket = "${local.name_prefix}-logs"
tags = local.common_tags # ← 同じ tags をそのまま使える
}
# data バケットも同じ local を使う → 名前付けとタグが揃う
resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data"
tags = local.common_tags
}
注意
ブロック名は
locals(複数形)ですが、参照は local.NAME(単数形)です。間違えやすいポイント。
output(出力)
「root モジュール」(プロジェクト直下)の output は terraform apply の最後に CLI に表示されます。「子モジュール」の output は親から module.NAME.OUTPUT で参照できます。
# シンプルな output: 単一の値を返す
# 参照: root module なら CLI 表示、子 module なら module.NAME.vpc_id で取れる
output "vpc_id" {
description = "作成した VPC の ID"
value = aws_vpc.main.id
}
# for 式で list を作って返す
# aws_subnet.public は for_each で作られた map 想定 → 各 s の id を集めた list
output "public_subnet_ids" {
value = [for s in aws_subnet.public : s.id]
}
# 機密値は sensitive = true でマスク
# → terraform output しても と表示される(state には平文で残るので注意)
output "db_password" {
value = random_password.db.result
sensitive = true
}
子モジュールの出力を親で使う
# 親 (root)
module "network" {
source = "./modules/network"
cidr = "10.0.0.0/16"
}
resource "aws_instance" "web" {
subnet_id = module.network.public_subnet_ids[0] # ← 子の output を参照
# ...
}