LESSON 30分

変数とモジュール

ストーリー

「staging環境とproduction環境で、ほぼ同じインフラを 作りたいとする。コードをコピペするか?」

木村先輩が質問した。

「コピペは......DRY原則に反しますよね」

「その通り。変数とモジュールを使えば、 同じコードを再利用しつつ、環境ごとの差異だけを パラメータで切り替えられる。 これがTerraformでインフラを効率的に管理する鍵だ」


変数(Variables)

入力変数(variable)

hcl
# variables.tf

# 基本的な変数定義
variable "environment" {
  description = "環境名 (staging / production)"
  type        = string
  default     = "staging"
}

variable "instance_type" {
  description = "EC2インスタンスタイプ"
  type        = string
  default     = "t3.micro"
}

variable "instance_count" {
  description = "EC2インスタンス数"
  type        = number
  default     = 1
}

variable "enable_monitoring" {
  description = "詳細モニタリングを有効にするか"
  type        = bool
  default     = false
}

# バリデーション付き変数
variable "environment" {
  description = "環境名"
  type        = string

  validation {
    condition     = contains(["staging", "production"], var.environment)
    error_message = "environment は staging または production を指定してください。"
  }
}

変数の型

説明
string"hello"文字列
number42数値
booltrue真偽値
list(string)["a", "b"]文字列のリスト
map(string){ key = "val" }文字列のマップ
object({...})複合型構造化されたオブジェクト

複合型の例

hcl
variable "vpc_config" {
  description = "VPC設定"
  type = object({
    cidr_block = string
    subnets    = list(object({
      cidr = string
      az   = string
    }))
  })
  default = {
    cidr_block = "10.0.0.0/16"
    subnets = [
      { cidr = "10.0.1.0/24", az = "ap-northeast-1a" },
      { cidr = "10.0.2.0/24", az = "ap-northeast-1c" },
    ]
  }
}

変数の値を指定する方法

変数値の優先順位(上が最優先)

1. コマンドライン引数  terraform apply -var="environment=production"
2. terraform.tfvars     environment = "production"
3. *.auto.tfvars        自動読み込み
4. 環境変数            TF_VAR_environment=production
5. default値           variable "environment" { default = "staging" }

terraform.tfvars

hcl
# terraform.tfvars(環境ごとに作成)
environment   = "production"
instance_type = "t3.large"
instance_count = 3
enable_monitoring = true
hcl
# staging.tfvars
environment   = "staging"
instance_type = "t3.micro"
instance_count = 1
enable_monitoring = false
bash
# 環境ごとにファイルを指定して実行
terraform plan -var-file="staging.tfvars"
terraform plan -var-file="production.tfvars"

ローカル変数(locals)

計算結果や繰り返し使う値を定義します。

hcl
locals {
  # 共通タグ
  common_tags = {
    Environment = var.environment
    Project     = "my-project"
    ManagedBy   = "terraform"
  }

  # 計算値
  name_prefix = "${var.project}-${var.environment}"

  # 条件分岐
  instance_type = var.environment == "production" ? "t3.large" : "t3.micro"
}

# 使用例
resource "aws_instance" "web" {
  instance_type = local.instance_type
  tags          = merge(local.common_tags, {
    Name = "${local.name_prefix}-web"
  })
}

モジュール(Module)

モジュールとは

再利用可能なTerraformコードのパッケージです。

モジュールの構成

modules/
└── vpc/
    ├── main.tf         ← リソース定義
    ├── variables.tf    ← 入力変数
    ├── outputs.tf      ← 出力値
    └── README.md       ← ドキュメント

environments/
├── staging/
│   └── main.tf         ← モジュールを呼び出す
└── production/
    └── main.tf         ← 同じモジュールを異なるパラメータで呼び出す

モジュールの定義

hcl
# modules/vpc/variables.tf
variable "name" {
  description = "VPC名"
  type        = string
}

variable "cidr_block" {
  description = "VPC CIDR"
  type        = string
  default     = "10.0.0.0/16"
}

variable "public_subnets" {
  description = "パブリックサブネットのCIDR"
  type        = list(string)
  default     = ["10.0.1.0/24", "10.0.2.0/24"]
}
hcl
# modules/vpc/main.tf
resource "aws_vpc" "this" {
  cidr_block           = var.cidr_block
  enable_dns_hostnames = true

  tags = {
    Name = var.name
  }
}

resource "aws_subnet" "public" {
  count             = length(var.public_subnets)
  vpc_id            = aws_vpc.this.id
  cidr_block        = var.public_subnets[count.index]
  availability_zone = data.aws_availability_zones.available.names[count.index]

  tags = {
    Name = "${var.name}-public-${count.index + 1}"
  }
}

data "aws_availability_zones" "available" {
  state = "available"
}
hcl
# modules/vpc/outputs.tf
output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.this.id
}

output "public_subnet_ids" {
  description = "パブリックサブネットのID"
  value       = aws_subnet.public[*].id
}

モジュールの呼び出し

hcl
# environments/staging/main.tf
module "vpc" {
  source = "../../modules/vpc"

  name           = "staging-vpc"
  cidr_block     = "10.0.0.0/16"
  public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}

# モジュールの出力を参照
resource "aws_instance" "web" {
  subnet_id = module.vpc.public_subnet_ids[0]
}
hcl
# environments/production/main.tf
module "vpc" {
  source = "../../modules/vpc"

  name           = "production-vpc"
  cidr_block     = "10.1.0.0/16"
  public_subnets = ["10.1.1.0/24", "10.1.2.0/24", "10.1.3.0/24"]
}

Terraform Registry のモジュール

コミュニティが公開しているモジュールも利用できます。

hcl
# Terraform Registry の VPC モジュール
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  single_nat_gateway = true
}

count と for_each

count

同じリソースを複数作成します。

hcl
resource "aws_instance" "web" {
  count         = var.instance_count
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type

  tags = {
    Name = "web-${count.index + 1}"
  }
}

for_each

マップやセットを使って複数リソースを作成します。

hcl
variable "subnets" {
  default = {
    public-a  = { cidr = "10.0.1.0/24", az = "ap-northeast-1a" }
    public-c  = { cidr = "10.0.2.0/24", az = "ap-northeast-1c" }
  }
}

resource "aws_subnet" "this" {
  for_each          = var.subnets
  vpc_id            = aws_vpc.main.id
  cidr_block        = each.value.cidr
  availability_zone = each.value.az

  tags = {
    Name = each.key
  }
}

まとめ

ポイント内容
variable入力パラメータ、型指定とバリデーション可能
locals計算値や繰り返し値の定義
module再利用可能なTerraformコードパッケージ
count/for_eachリソースの複数作成

チェックリスト

  • variable の定義と値の指定方法を理解した
  • locals で計算値を定義できる
  • モジュールの作成と呼び出し方を理解した
  • count と for_each の使い分けを把握した

次のステップへ

次のセクションでは、Terraformの実行ワークフロー(plan/apply/destroy)を詳しく学びます。


推定読了時間: 30分