0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【IaC超入門】30日でAWS CloudFormationとTerraformをマスターするロードマップ - 22日目: TerraformのStateファイルを管理する方法(Terraform Cloud, S3)

Last updated at Posted at 2025-08-28

Terraformのモジュールを使ってコードを再利用する

はじめに

これまでの学習で、変数を使ってTerraformコードを柔軟にすることはできるようになりました。しかし、VPCやEC2など、複数のリソースを組み合わせたインフラを毎回手動で定義するのは効率的ではありません。今回は、これらのまとまりを「部品」として再利用可能にするための重要な機能、 モジュール(Modules) について解説します。

1. モジュールとは?

モジュールは、関連する複数のリソースを一つの論理的な単位としてカプセル化(まとめる)する機能です。これにより、複雑なインフラをシンプルに、そして再利用可能な形で管理できます。

例えば、VPCと複数のサブネット、ルートテーブル、インターネットゲートウェイといったネットワーク関連のリソース群を一つの「ネットワークモジュール」として作成し、他のプロジェクトで簡単に呼び出して使えるようになります。

2. モジュールの種類

Terraformには、主に2種類のモジュールがあります:

  • ルートモジュール: terraform planterraform applyを実行するディレクトリそのものです。これまでのハンズオンで作成してきたコードは、すべてルートモジュールに属します。
  • 子モジュール: ルートモジュールから呼び出される、再利用可能なコードブロックです。

3. モジュールの基本的な使い方

モジュールは、moduleブロックを使って呼び出します。実際の例を見てみましょう。

ステップ1:子モジュールの作成

まず、再利用したいコードを別のディレクトリに配置します。例えば、modules/vpcというディレクトリを作成し、その中に必要なTerraformファイルを配置します。

ディレクトリ構造

project/
├── main.tf
├── variables.tf
├── outputs.tf
└── modules/
    └── vpc/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

modules/vpc/variables.tf

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

variable "public_subnet_cidr" {
  description = "CIDR block for public subnet"
  type        = string
  default     = "10.0.1.0/24"
}

variable "availability_zone" {
  description = "Availability zone for subnet"
  type        = string
  default     = "ap-northeast-1a"
}

variable "project_name" {
  description = "Name of the project"
  type        = string
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "dev"
}

modules/vpc/main.tf

# VPCリソース
resource "aws_vpc" "this" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name        = "${var.project_name}-${var.environment}-vpc"
    Environment = var.environment
  }
}

# インターネットゲートウェイ
resource "aws_internet_gateway" "this" {
  vpc_id = aws_vpc.this.id

  tags = {
    Name        = "${var.project_name}-${var.environment}-igw"
    Environment = var.environment
  }
}

# パブリックサブネット
resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.this.id
  cidr_block              = var.public_subnet_cidr
  availability_zone       = var.availability_zone
  map_public_ip_on_launch = true

  tags = {
    Name        = "${var.project_name}-${var.environment}-public-subnet"
    Environment = var.environment
    Type        = "Public"
  }
}

# ルートテーブル(パブリック)
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.this.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.this.id
  }

  tags = {
    Name        = "${var.project_name}-${var.environment}-public-rt"
    Environment = var.environment
  }
}

# ルートテーブルアソシエーション
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public.id
}

modules/vpc/outputs.tf

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

output "vpc_cidr_block" {
  description = "CIDR block of the VPC"
  value       = aws_vpc.this.cidr_block
}

output "public_subnet_id" {
  description = "ID of the public subnet"
  value       = aws_subnet.public_subnet.id
}

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

ステップ2:ルートモジュールからの呼び出し

次に、ルートモジュール(main.tfがあるディレクトリ)から、先ほど作成した子モジュールを呼び出します。

main.tf

terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

# VPCモジュールを呼び出す
module "my_network" {
  source = "./modules/vpc" # 子モジュールのパスを指定

  vpc_cidr           = "10.0.0.0/16"
  public_subnet_cidr = "10.0.1.0/24"
  availability_zone  = "ap-northeast-1a"
  project_name       = "my-project"
  environment        = "dev"
}

# 最新のAmazon Linux 2 AMIを取得
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}

# セキュリティグループ
resource "aws_security_group" "web_sg" {
  name_prefix = "web-sg-"
  vpc_id      = module.my_network.vpc_id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web-security-group"
  }
}

# EC2インスタンス
resource "aws_instance" "web_server" {
  ami                    = data.aws_ami.amazon_linux.id
  instance_type          = "t3.micro"
  subnet_id              = module.my_network.public_subnet_id
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = {
    Name = "web-server"
  }
}

moduleブロック内のsourceで、呼び出したい子モジュールのパスを指定します。子モジュールのvariableに値を渡すことで、再利用時にカスタマイズできます。outputは、module.<モジュール名>.<出力名>の形式で参照できます。

4. モジュールの実行手順

モジュールを含むTerraformコードを実行する際の手順:

# 1. 初期化(モジュールのダウンロード)
terraform init

# 2. プランの確認
terraform plan

# 3. 実行
terraform apply

terraform initを実行すると、Terraformはモジュールを.terraform/modules/ディレクトリにダウンロード・コピーします。

5. モジュールのベストプラクティス

ファイル構成

モジュールは以下の3つのファイルに分けることを推奨します:

  • main.tf: リソース定義
  • variables.tf: 入力変数の定義
  • outputs.tf: 出力値の定義

変数の型指定と説明

variable "instance_count" {
  description = "Number of EC2 instances to create"
  type        = number
  default     = 1
  
  validation {
    condition     = var.instance_count > 0 && var.instance_count <= 10
    error_message = "Instance count must be between 1 and 10."
  }
}

バージョン管理

本格的な運用では、モジュールをGitリポジトリで管理し、タグを使ってバージョンを指定します:

module "vpc" {
  source = "git::https://github.com/your-org/terraform-aws-vpc.git?ref=v1.2.0"
  
  # 変数の指定...
}

6. モジュールのメリット

メリット 説明
再利用性の向上 一度作成したモジュールは、複数のプロジェクトで簡単に使い回せる
コードの抽象化 複雑なリソース群を一つのブロックとして扱い、コード全体をシンプルにする
保守性の向上 モジュール内で変更が必要な場合、そのモジュールだけを修正すればよい
標準化の促進 チーム内でのインフラ構成を統一し、ベストプラクティスを共有できる
テストしやすさ 個別のモジュール単位でテストが可能

7. 注意点

モジュールの変更時

モジュールを変更した場合は、以下のコマンドでモジュールを更新します:

terraform get -update

循環参照の回避

モジュール間で循環参照が発生しないよう、依存関係を明確に設計しましょう。

セキュリティ

外部のモジュールを使用する際は、コードの内容を十分に確認してからご使用ください。

まとめ

モジュールは、Terraformを大規模なプロジェクトで活用する上で不可欠な機能です。VPCやセキュリティグループ、EC2など、関連するリソースをモジュールとして分割することで、コードの重複をなくし、より保守性の高いインフラ管理を実現できます。

次回は、これまでのTerraformの知識を総動員して、より実践的なWordPress環境の構築に挑戦します。お楽しみに!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?