基本機能

モジュール

Terraformのモジュールは、再利用可能なインフラストラクチャコンポーネントを作成するための仕組みです。このページでは、モジュールの概念、作成方法、使用方法について説明します。
最終更新: 2026/2/17

モジュール

Terraformのモジュールは、再利用可能なインフラストラクチャコンポーネントを作成するための仕組みです。このページでは、モジュールの概念、作成方法、使用方法について説明します。

モジュールとは

モジュールは、複数のリソースをまとめた再利用可能なコンポーネントです。関連するリソースをグループ化し、抽象化することで、コードの重複を削減し、保守性を向上させます。

モジュールの利点

  1. 再利用性: 同じ構成を複数の場所で使用できる
  2. 保守性: 変更を一箇所で行うだけで、すべての使用箇所に反映
  3. 抽象化: 複雑な実装を隠蔽し、シンプルなインターフェースを提供
  4. 標準化: 組織全体でベストプラクティスを共有
  5. テスト: モジュール単位でテストが可能

モジュールの種類

ルートモジュール

Terraformを実行するディレクトリのことをルートモジュールと呼びます。すべてのTerraform設定はルートモジュールから始まります。

.
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars

子モジュール

他のモジュールから呼び出されるモジュールです。

.
├── main.tf
└── modules/
    ├── vpc/
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    └── ec2/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

モジュールの作成

基本的なモジュール構造

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

実践例: VPCモジュール

modules/vpc/main.tf:

resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = var.enable_dns_hostnames
  enable_dns_support   = var.enable_dns_support
  
  tags = merge(
    var.tags,
    {
      Name = var.vpc_name
    }
  )
}

resource "aws_subnet" "public" {
  count = length(var.public_subnet_cidrs)
  
  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.public_subnet_cidrs[count.index]
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true
  
  tags = merge(
    var.tags,
    {
      Name = "${var.vpc_name}-public-${count.index + 1}"
      Type = "Public"
    }
  )
}

resource "aws_subnet" "private" {
  count = length(var.private_subnet_cidrs)
  
  vpc_id            = aws_vpc.main.id
  cidr_block        = var.private_subnet_cidrs[count.index]
  availability_zone = var.availability_zones[count.index]
  
  tags = merge(
    var.tags,
    {
      Name = "${var.vpc_name}-private-${count.index + 1}"
      Type = "Private"
    }
  )
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  
  tags = merge(
    var.tags,
    {
      Name = "${var.vpc_name}-igw"
    }
  )
}

modules/vpc/variables.tf:

variable "vpc_name" {
  description = "Name of the VPC"
  type        = string
}

variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string
  default     = "10.0.0.0/16"
}

variable "public_subnet_cidrs" {
  description = "CIDR blocks for public subnets"
  type        = list(string)
  default     = ["10.0.1.0/24", "10.0.2.0/24"]
}

variable "private_subnet_cidrs" {
  description = "CIDR blocks for private subnets"
  type        = list(string)
  default     = ["10.0.11.0/24", "10.0.12.0/24"]
}

variable "availability_zones" {
  description = "Availability zones"
  type        = list(string)
}

variable "enable_dns_hostnames" {
  description = "Enable DNS hostnames in the VPC"
  type        = bool
  default     = true
}

variable "enable_dns_support" {
  description = "Enable DNS support in the VPC"
  type        = bool
  default     = true
}

variable "tags" {
  description = "Tags to apply to resources"
  type        = map(string)
  default     = {}
}

modules/vpc/outputs.tf:

output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}

output "vpc_cidr" {
  description = "CIDR block of the VPC"
  value       = aws_vpc.main.cidr_block
}

output "public_subnet_ids" {
  description = "IDs of public subnets"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "IDs of private subnets"
  value       = aws_subnet.private[*].id
}

output "internet_gateway_id" {
  description = "ID of the Internet Gateway"
  value       = aws_internet_gateway.main.id
}

モジュールの使用

ローカルモジュールの使用

# main.tf
module "vpc" {
  source = "./modules/vpc"
  
  vpc_name             = "production-vpc"
  vpc_cidr             = "10.0.0.0/16"
  public_subnet_cidrs  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24"]
  availability_zones   = ["ap-northeast-1a", "ap-northeast-1c"]
  
  tags = {
    Environment = "Production"
    ManagedBy   = "Terraform"
  }
}

# モジュールの出力を参照
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  subnet_id     = module.vpc.public_subnet_ids[0]
  
  tags = {
    Name = "WebServer"
  }
}

Terraform Registryのモジュールを使用

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"
  
  name = "my-vpc"
  cidr = "10.0.0.0/16"
  
  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
  
  enable_nat_gateway = true
  enable_vpn_gateway = false
  
  tags = {
    Environment = "Production"
  }
}

Gitリポジトリのモジュールを使用

module "vpc" {
  source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=v1.0.0"
  
  vpc_name = "production-vpc"
  vpc_cidr = "10.0.0.0/16"
}

モジュールの初期化

モジュールを使用する場合、初期化が必要です。

terraform init

モジュールのソースを変更した場合:

terraform init -upgrade

モジュールの入力と出力

入力変数

モジュールへの入力は変数を通じて行います。

module "vpc" {
  source = "./modules/vpc"
  
  # 入力変数
  vpc_name = "my-vpc"
  vpc_cidr = "10.0.0.0/16"
}

出力値

モジュールからの出力はoutputブロックで定義します。

# モジュール内(modules/vpc/outputs.tf)
output "vpc_id" {
  value = aws_vpc.main.id
}

# ルートモジュール(main.tf)
output "vpc_id" {
  value = module.vpc.vpc_id
}

モジュール間でのデータの受け渡し

module "vpc" {
  source = "./modules/vpc"
  
  vpc_name = "production-vpc"
  vpc_cidr = "10.0.0.0/16"
}

module "ec2" {
  source = "./modules/ec2"
  
  vpc_id    = module.vpc.vpc_id
  subnet_id = module.vpc.public_subnet_ids[0]
}

モジュールのバージョニング

セマンティックバージョニング

モジュールのバージョンは、セマンティックバージョニング(SemVer)に従うことが推奨されます。

  • MAJOR: 互換性のない変更
  • MINOR: 後方互換性のある機能追加
  • PATCH: 後方互換性のあるバグ修正
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"  # 5.0.x の最新版を使用
}

バージョン制約

# 特定のバージョン
version = "5.0.0"

# バージョン範囲
version = ">= 5.0.0, < 6.0.0"

# ペシミスティック制約(推奨)
version = "~> 5.0"  # 5.0.x の最新版
version = "~> 5.0.0"  # 5.0.0 以上 5.1.0 未満

モジュールの構成パターン

単一責任の原則

各モジュールは1つの責任を持つべきです。

modules/
├── vpc/          # VPCの管理
├── ec2/          # EC2インスタンスの管理
├── rds/          # RDSの管理
└── s3/           # S3バケットの管理

階層的なモジュール構成

modules/
├── networking/
│   ├── vpc/
│   ├── subnet/
│   └── security-group/
├── compute/
│   ├── ec2/
│   └── autoscaling/
└── storage/
    ├── s3/
    └── ebs/

コンポジションパターン

複数のモジュールを組み合わせて、より大きなシステムを構築します。

module "networking" {
  source = "./modules/networking"
  
  vpc_cidr = "10.0.0.0/16"
}

module "compute" {
  source = "./modules/compute"
  
  vpc_id    = module.networking.vpc_id
  subnet_id = module.networking.public_subnet_ids[0]
}

module "database" {
  source = "./modules/database"
  
  vpc_id     = module.networking.vpc_id
  subnet_ids = module.networking.private_subnet_ids
}

モジュールのテスト

Terraformのvalidateコマンド

cd modules/vpc
terraform init
terraform validate

Terraformのplanコマンド

terraform plan

自動テスト

Terratest(Go)やKitchen-Terraform(Ruby)などのツールを使用して、モジュールの自動テストを実行できます。

ベストプラクティス

1. 明確なインターフェースを定義

# 必須の変数には説明を追加
variable "vpc_name" {
  description = "Name of the VPC"
  type        = string
}

# オプションの変数にはデフォルト値を設定
variable "enable_dns_hostnames" {
  description = "Enable DNS hostnames in the VPC"
  type        = bool
  default     = true
}

2. 出力値を適切に定義

output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}

3. READMEを作成

各モジュールにREADME.mdを作成し、使用方法を文書化します。

# VPC Module

## Usage

```hcl
module "vpc" {
  source = "./modules/vpc"
  
  vpc_name = "my-vpc"
  vpc_cidr = "10.0.0.0/16"
}

Inputs

NameDescriptionTypeDefaultRequired
vpc_nameName of the VPCstringn/ayes
vpc_cidrCIDR block for the VPCstring"10.0.0.0/16"no

Outputs

NameDescription
vpc_idID of the VPC

### 4. バージョン管理

モジュールをGitリポジトリで管理し、タグを使用してバージョンを管理します。

```bash
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0

5. 変数の検証

variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string
  
  validation {
    condition     = can(cidrhost(var.vpc_cidr, 0))
    error_message = "The vpc_cidr must be a valid CIDR block."
  }
}

6. 機密情報の扱い

variable "db_password" {
  description = "Database password"
  type        = string
  sensitive   = true
}

output "db_endpoint" {
  description = "Database endpoint"
  value       = aws_db_instance.main.endpoint
  sensitive   = true
}

Terraform Registry

モジュールの公開

  1. GitHubリポジトリを作成(命名規則: terraform-<PROVIDER>-<NAME>
  2. モジュールを実装
  3. タグを作成(例: v1.0.0)
  4. Terraform Registryに登録

モジュールの検索

Terraform Registryで、公開されているモジュールを検索できます。

次のステップ

モジュールの基本を理解したら、ベストプラクティスについて学びましょう。

参考リンク

© 2026 IBM Corporation. Licensed under CC BY 4.0.