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?

【Terraform】モジュール化の仕組みを理解するための要点

Last updated at Posted at 2025-12-14

Terraformモジュールの概要

Terraform を小規模に使っているうちは1つの main.tf にコードを書くだけで十分ですが、
環境が増えたり、チーム開発になったりすると必ず モジュール化 が必要になってきます。

◇ terraformのモジュールとは?

Terraformのモジュールは、"フォルダ単位でまとめたインフラ構成の部品" のことです。
AWSなら、VPC・EC2・S3といったリソースごとに部品化して使い回せます。

◇ terraformをモジュール化するには?

Terraform でモジュール設計を検討する場合は、
「root モジュール」と「child モジュール」の二層構造 を意識すれば理解できると思います。

例えば s3 と iam をtest(テスト環境)とprod(本番環境)でデプロイする場合、
以下のようなファイルレイアウトにすると、これが "モジュール化された構成" になります。

ファイルレイアウトの例
terraform/
├── modules/
│   ├── s3/    ← 部品ごとの "child モジュール"
│   │   ├── main.tf
│   │   └── ...
│   │
│   └── iam/    ← 部品ごとの "child モジュール"
│       ├── main.tf
│       └── ...
│
├── test/    ← 環境ごとの "root モジュール"
│   ├── main.tf
│   └── ...
│
└── prod/    ← 環境ごとの "root モジュール"
    └── ...

◇ モジュール化したterraformをデプロイするには?

重要な点として、
terraform apply必ず "root モジュール" で実行します。
modules/の階層、つまり"child モジュール" でapplyを実行すると、意図しないリソースが作成される場合があるので注意してください。

applyの実行場所
terraform/
├── modules/    ← ✕ ここでは apply しない
├── test/       ← 〇 apply を実行する場所
└── prod/       ← 〇 apply を実行する場所

◇ この記事で扱う内容

この記事では、terraformモジュールを扱う上で重要な次の項目についてまとめています。

【目次】

  1. ファイルレイアウトとモジュールの関係
  2. root から child を呼び出す文法
  3. モジュールで扱う変数
    3.1. モジュールの入力変数(variable)
    3.2. モジュール内で定義する locals
    3.3. モジュールの出力変数(output)

1.ファイルレイアウトとモジュールの関係

◇ モジュールの単位は "ファイルレイアウト" で決まる

モジュールの単位を一言で定義するなら "一意のフォルダ" になります。
そのフォルダに存在する .tf ファイル群が "ひとつのモジュール" を構成します。

ファイルレイアウトの例
modules/s3/     ← このフォルダ全体が "1つのモジュール"
    ├── main.tf
    ├── variables.tf
    └── outputs.tf

逆にいうと、フォルダが違えばそれは 全く別のモジュール になります。

ファイルレイアウトの例
terraform/
├── modules/
│   ├── s3/      ← "モジュール A"
│   │   ├── main.tf
│   │   └── ...
│   │
│   └── iam/     ← "モジュール B"
│       ├── main.tf
│       └── ...

2.root から child を呼び出す文法

◇ モジュールの基本構造は、
 "root モジュール" が "child モジュール" を呼び出す

Terraform のモジュールは大きく二つに分類されます。

  • root モジュール :"child モジュール" を呼び出し、apply を実行する場所
  • child モジュール :"root モジュール" に呼び出されるモジュール

最初のファイルレイアウトでみると、次のようなイメージになります。

ファイルレイアウトの例
terraform/
├── modules/
│   ├── s3/    ← "child モジュール"
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   │
│   └── iam/    ← "child モジュール"
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
│
├── test/    ← "root モジュール"
│   ├── main.tf
│   └── backend.tf (任意)
│
└── prod/    ← "root モジュール"
    ├── main.tf
    └── backend.tf (任意)

このファイルレイアウトの場合、
test / prod はそれぞれ独立した root モジュールになります。

それぞれが modules/s3 や modules/iam といった child モジュールを呼び出し、
環境ごとに別の state(test 用 / prod 用)を持つことになります。

◇ モジュールを呼び出す方法

test/prod の root モジュールで child モジュールを呼び出す際は、
root モジュール側の "main.tf" に次の文法を記述します。

root モジュール側の main.tf
module "<NAME>" {
  source      = "<SOURCE>"

  [CONFIG]
}

例えば、"s3 バケット"を呼び出す場合は、main.tfに次のようなコードを記述します。

main.tfの例
module "logs_bucket" {
  source      = "../modules/s3"

  [CONFIG]
}

各コードの意味は次のとおりです。

  • "logs_bucket"
    root モジュールでchild モジュールを識別するための名前(自由に決められる)
  • source = "../modules/s3"
    child モジュールのコードが置かれているパス(相対パス or Git / Registry も可)

これで、root モジュール から child モジュール を呼び出すための基本構造が整います。
ただし、モジュールは呼び出すだけでは真価を発揮しません。

Terraform のモジュールでは、
環境ごとに異なる値を渡したり、モジュール内部で共通の計算値を扱ったり、外へ値を返したりするための仕組み として、いくつかの変数が用意されています。

これらの仕組みについては、次章「3. モジュールで扱う変数」で解説します。

3. モジュールで扱う変数

Terraform では、モジュール内部で扱うためのいくつかの変数が用意されています。

仕組みを知らないうちは「変数が多くてややこしい、、」と感じますが、
「どの変数がどの方向に流れるのか」
というイメージを掴めば、理解がシンプルになります。

モジュールで扱う変数の関係をイメージ図で表現してみました。

◆ イメージ図(モジュールと変数の関係)
モジュール変数イメージ図 (2).png

Terraform のモジュールで使う変数は大きく次の3種類に分かれます。

1. 入力変数(variable)
root モジュール → child モジュール に値を渡すための変数。
外からモジュールへ届けられるパラメータです。
2. ローカル変数(locals)
モジュール内部でのみ利用される "計算用・共通化用の値"。
※root と child の間を行き来することはありません。
3. 出力変数(output)
child モジュール → root モジュール に値を返すための変数。
モジュールから外へ返す結果を出力します。

この3種類の変数について、もう少し詳しく解説します。

3.1. モジュールの入力変数(variable)

◇ 入力変数について

入力変数(variable)は、
root モジュール → child モジュールへ値を渡すための仕組み です。

Terraform のモジュールは、
「環境ごとに値を変えたい部分」や「再利用したい設定」を部品化して使いますが、
その際に child モジュールへ柔軟に値を渡すために variable を使用します。

◆ イメージ図(コードの関係)
入力変数コード関係 (3).png


root 側から渡したパラメータがchild モジュール内の var. として参照され、
リソースの設定値として利用される流れを視覚化してみました。

次のような利用シーンがあります。

  • test / prod で値を変えたい
    例:S3バケット名、タグ、環境名などをchildモジュールに渡す
  • モジュールの再利用性を高めたい
    例:同じ IAM ロール定義を、「環境依存の値」だけ変えて複数環境で使い回す
  • child モジュール側で固定値を書かずに済ませたい
    → ハードコーディングを避け、保守性を向上させる

要するに、
「環境の違いで変わる値はすべて root モジュール側で制御し、child モジュールは variable 経由でその値を受け取るだけにする」
というのが、入力変数の本質だと思います。
こうしておくことで、環境差異による変更は root 側の variable を変えるだけで済み、child モジュールのコードは一切触らずに済みます。

◇ 入力変数を設定するポイント

■ child モジュール側

  1. variable "<入力変数名>" {}で受け取る入力変数を定義しておく
  2. "main.tf"内のvar.<入力変数名>で入力変数を受け取ってリソースに反映する

■ root モジュール側

  1. "main.tf"内のmodule "<モジュール名>" { ... }でモジュールを呼び出す
  2. "main.tf"内の<入力変数名> = "代入したい値"で child 側に値を渡す

このステップさえ押さえれば、
入力変数(variable) によって、環境差分を root 側で制御した扱いやすいモジュール構造が実現します。

3.2. モジュール内で定義する locals

◇ ローカル変数について

ローカル変数(locals)は、
モジュール内部だけで使う "計算用・共通化用の値" をまとめる仕組み です。

入力変数(variable)が「外から渡される値」を扱うのに対し、
locals は 「モジュールの内側で完結する値」 を整理するための変数になります。

◆ イメージ図(コードの関係)
入力変数コード関係(local) (1).png


root モジュールから child モジュールへ渡した var を材料として、
child 内部の locals が値を計算し、その結果を main.tf のリソース設定に反映する流れを視覚化しています。
locals はあくまでモジュール内部だけで完結する "計算・共通化用の領域" であり、
外部へ直接値を渡すことはありません。

次のような利用シーンがあります。

  • root から渡された値をもとに、モジュール内部で新しい値を生成したい
    例:"${var.env}-${local.project}" のような命名規則の統一
  • 複雑な式をmain.tfで可読性の高い "名前付きの値" で参照したい
    例:performance_tier = var.env == "prod" ? "HIGH" : "LOW" を locals.tf 内で定義しておき、local.performance_tier としてリソース側から参照する

まとめると、
locals は child モジュール内の整形・共通化 が主な役割です。

◇ ローカル変数を設定するポイント

■ child モジュール側

  1. "locals.tf"などに、locals {<ローカル変数> = "代入したい値"}でローカル変数を定義する
  2. "main.tf"内のlocal.<ローカル変数名>"でローカル変数を受け取ってリソースに反映する

このステップを押さえておけば、
ローカル変数(locals) を活用して、child モジュール内部の main.tf を整理された、読みやすい構造に保つことができます。

3.3. モジュールの出力変数(output)

◇ 出力変数について

出力変数(output)は、
child の内部で計算された値を root 側へ返却する仕組み です。

child モジュール内部では、locals やリソースによって「内部でしか見えない値」が生成されますが、
そのままでは root モジュールから参照することはできません。

◆ イメージ図(コードの関係)
出力変数コード関係 (1).png

次のような利用シーンがあります。

  • child モジュール内で生成した値を root モジュール側で参照したい
    例:S3 バケット名、IAM ロール ARN、作成したリソースの ID など
  • 別の child モジュールへ渡したい値を、一度 root 側で受け取る必要がある
    例:VPC モジュールが返す subnet ID を EC2 モジュールへ渡す
  • child モジュールをブラックボックス化し、必要な情報だけ外に公開したい
    → 内部構造を隠蔽し、インターフェースだけ提供するための設計意図

つまり、
出力変数は(output)とは、
child モジュールで生成したものを、root モジュールが受け取るための "出口" です。

◇ 出力変数を設定するポイント

■ child モジュール側

  1. "outputs.tf" に output "<output名>" {value = <返したい値>} の形式で出力変数を定義する
  2. <返したい値>はモジュール内部で生成した aws_xxx.yyy.id などの値を指定する

■ root モジュール側

  1. "main.tf"内のmodule "<モジュール名>" { ... } でモジュールを呼び出す
  2. module.<モジュール名>.<output名> の形式で参照する
    ※出力がオブジェクトの場合は module.<モジュール名>.<output名>.<キー名>

このステップを押さえれば、
child モジュール内部で生成した値をroot モジュール側のリソース設定に反映することができます。

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?