ハブ記事: Terraform モジュール 完全ガイド →
設計・配布・運用まで Terraform モジュールの全体像を一望できるハブ記事
Terraformは同じ結果でも設計の切り方で運用コストと失敗時の影響が大きく変わります。本稿では単機能モジュール、コンポジットモジュール、レイヤーモデルを使い分けるための具体指針を示します。
HashiCorp公式の一般的な挙動に基づき、安定的な概念に絞って説明します。機能は各クラウドやバージョンで差異が出やすいため、パターン選定は保守性と適用順序の明確化を優先します。
単機能モジュールは、1つの明確な責務(例: VPC、サブネット、セキュリティグループなど)に集中し、入力と出力を最小限に絞ります。コンポジットモジュールは、複数の単機能モジュールを束ね、ガードレールや標準設定を内包して再利用性を高めます。レイヤーは、ルートモジュール(スタック)を境界として、適用順序や責任分離を保つための構造です(例: Bootstrap、Network、Platform、Application)。
実務では、単機能で細かく分割し過ぎると利用側の負荷が上がり、逆に巨大なコンポジットや単一レイヤーに寄せすぎると失敗時の影響範囲が広がります。組織の変更頻度と運用体制に合わせたバランスが重要です。
| 観点 | 単機能モジュール | コンポジットモジュール | レイヤー(ルートモジュール) |
|---|---|---|---|
| 目的 | 責務を最小化し再利用性を高める | 単機能を組み合わせて標準を内包 | 適用順序と境界の明確化 |
| 責務範囲 | リソース種別または小さなまとまり | ワークロード単位やドメイン単位 | インフラの階層(Network/Platform/App等) |
| 入出力の粒度 | 少数・厳格な型・安定した出力 | 入力はまとめたオブジェクト、出力は代表値 | 他レイヤーに渡す最小のアウトプット |
| 依存関係の扱い | 明示的に親へ委ねる | 子モジュール間の順序は内部で調整 | 他レイヤーとは出力を介して疎結合 |
| 適用シーン | 単体の部品化、テスト容易性重視 | 標準構成の迅速展開 | 環境分離、責任分担、並列デプロイ |
| 失敗時の影響 | 小さい(ロールバック容易) | 中程度(束ねた範囲) | 大きいが境界外には波及しづらい |
単機能モジュールは、入力の型を厳格にし、デフォルトとバリデーションを活用して利用者の誤入力を防ぎます。出力は後段で必要な最小限に絞り、破壊的変更が発生しにくい設計にします。
変数はスカラーや小さなオブジェクトに留め、曖昧なマップで何でも受ける設計は避けます。出力に機微情報が含まれる場合は sensitive を付与し、上位の plan 表示に不用意に露出しないようにします。
コンポジットモジュールは、単機能モジュールの配線図を固定化し、タグや暗号化、ログ取得などの組織標準を内包します。利用者は少数の入力を与えるだけで、標準準拠のスタックを得られます。
子モジュールにエイリアス付きプロバイダを渡す場合、providers マップで明示的に伝播する必要があります。for_each を使って複数の子を生成する場合は、安定したキー(例: 論理名)で差分を抑えます。
コンポジットモジュールの骨子例(network_stack)
variable "name" { type = string }
variable "region" { type = string }
variable "network" {
type = object({
cidr_block = string,
subnets = map(object({ az = string, cidr_block = string }))
})
}
variable "security_rules" { type = list(object({
description = string,
protocol = string,
from_port = number,
to_port = number,
cidr_blocks = list(string)
})) }
locals {
default_tags = { "managed-by" = "terraform", "stack" = var.name }
}
provider "aws" { region = var.region }
module "vpc" {
source = "../modules/vpc"
name = var.name
cidr_block = var.network.cidr_block
tags = local.default_tags
}
module "subnet" {
for_each = var.network.subnets
source = "../modules/subnet"
vpc_id = module.vpc.id
az = each.value.az
cidr_block = each.value.cidr_block
tags = local.default_tags
}
module "sg" {
source = "../modules/security_group"
vpc_id = module.vpc.id
name = "${var.name}-base"
rules = var.security_rules
tags = local.default_tags
}
output "vpc_id" { value = module.vpc.id }
output "subnet_ids" { value = [for s in module.subnet : s.id] }
output "security_group_id" { value = module.sg.id }レイヤーはルートモジュールの単位で分割し、適用順序を明確にします。典型例は Bootstrap(バックエンド・IAM最小権限)、Network(VPC等)、Platform(EKS/ECS/Compute基盤)、Application(サービス)の4層です。各レイヤーは独立した状態を持ち、他レイヤーとの連携は出力を通じて行います。
レイヤー間の依存は出力を介した疎結合に留めます。どうしても別レイヤーの値が必要な場合は、data.terraform_remote_state を使って読み出しますが、循環依存や過剰な参照に注意します。環境(dev/stg/prod)はディレクトリ分割とバックエンド分離で並列運用し、CIでレイヤー順に plan/apply します。
モジュールはセマンティックバージョニングを採用し、破壊的変更(入力名の変更、出力削除、リソース置換を強制する論理変更)はメジャーアップ時にまとめます。change log と移行手順を必ず添えます。
利用側では required_version と required_providers で Terraform本体とプロバイダを固定し、レジストリ配布のモジュールは version で制約します。子モジュールが特定のプロバイダ設定を要求する場合(alias 等)は、providers マップで明示的に渡せるようにドキュメント化します。
プロ試験では、責務分離、依存の取り扱い、プロバイダ伝播、for_each と count の選択、センシティブ情報の扱いが頻出です。モジュール境界での状態分離と、出力の最小化が正解に寄りやすい傾向があります。
アンチパターンとして、なんでも受けるマップ変数、巨大モジュールの一括適用、レイヤー跨ぎの過剰な remote_state 参照、可変なキーでの for_each、プロバイダ alias の未伝播などがあります。
Pro
問題 1
複数環境(dev/stg/prod)で、組織標準のタグ・暗号化・ネットワーク設計を強制しつつ、アプリごとの違いは最小限の入力で吸収したい。失敗時の影響範囲は小さく保ち、適用順序も明確にしたい。最も適切な設計はどれか。
正解: A
標準設定を内包したコンポジットで入力負荷と逸脱を抑え、レイヤー化で適用順序と状態境界を明確化するのが要件に合致します。巨大モノリスは影響範囲が広く、単機能の直列配線は入力負荷と逸脱リスクが高い。data のみでは作成と標準強制ができません。
環境分離はディレクトリとワークスペースのどちらを使うべきですか?
本番運用ではディレクトリ分割とバックエンド(状態)分離を基本にし、必要に応じてワークスペースを補助的に使います。これにより権限境界、ロック、ライフサイクルを環境ごとに独立させやすくなります。
レイヤー間の値受け渡しは変数で渡すか、terraform_remote_state を使うべきですか?
同一レイヤー内のモジュール間は変数・出力で直接渡し、レイヤーを跨ぐ場合のみ terraform_remote_state で最小限の出力を参照します。循環依存や過剰な参照は避け、境界は疎結合に保ちます.
プロバイダのバージョンと alias をモジュールでどう扱えばよいですか?
ルートで required_providers にバージョン範囲を明示し、必要なら別リージョン等に alias を定義します。子モジュールへは module ブロックの providers 引数で alias を明示的に渡します。モジュール側の README には期待するプロバイダ設定を記載し、互換性を保てるようにします。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける
Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...
Terraform Authoring & Ops Pro: 上位資格の範囲と対策
上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...
Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす
Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...
Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義
Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...
Terraform Data Source徹底理解:既存リソースの参照で壊さず足す
Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...