ようこそ、クラウドインフラの世界へ。今日から君も、コードで世界を定義する「Infrastructure as Code(IaC)」の探求者ですね。
私はこれまで、数千台規模のサーバー群を数分で構築し、一度のコマンドで大陸をまたぐインフラを制御する現場を渡り歩いてきました。その中で確信したことがあります。「Terraformは単なる構築ツールではなく、インフラの設計思想を表現する言語である」ということです。
Terraformを触り始めたばかりの君は、きっと「モジュール化して再利用性を高めよう!」という言葉を耳にするでしょう。しかし、ここに大きな罠があります。良かれと思って作ったモジュールが、数ヶ月後には「誰も触りたくない魔窟」に変わってしまう現場を、私は何度も見てきました。
今日は、Terraformの基本をしっかり押さえつつ、ベテランでも陥りがちな「保守性を下げるモジュール設計のアンチパターン」を伝授します。これをマスターすれば、君の書くコードは「芸術」へと昇華されるはずです。
—
1. Terraformの役割:なぜ「宣言的」である必要があるのか?
Terraformの最大の魅力は「宣言的(Declarative)」であることです。
「サーバーを1台立てて、次に設定を流し込んで…」という手順を書くのではありません。「あるべき姿(State)」を記述すれば、Terraformが現状(AS-IS)との差分を計算し、最短ルートで理想の状態(TO-BE)へと導いてくれます。
この「冪等性(べきとうせい:何度実行しても同じ結果になること)」こそが、現代のSREが最も大切にする概念です。
—
2. 準備:プロが選ぶ最小構成のセットアップ
まずは、君の手元を戦場(現場)で使える状態にしましょう。
インストールは `tfenv` が鉄則
Terraformは頻繁にアップデートされます。プロジェクトごとにバージョンを切り替えられるよう、直接インストールせず `tfenv` を使いましょう。
macOSの場合
brew install tfenv
最新の安定版をインストール
tfenv install latest
tfenv use latest
バージョン確認
terraform -v
最初の「Hello World」:S3バケットを作ってみる
まずは動作確認です。AWSを例にします。
main.tf
プロバイダーの設定:どのクラウドを使うか宣言
provider “aws” {
region = “ap-northeast-1” # 東京リージョン
}
リソースの定義:何を作るか宣言
resource “aws_s3_bucket” “hello_world” {
bucket = “my-unique-terraform-bucket-20231027” # 世界で唯一の名前に
}
コマンドは3ステップ。これだけは暗記してください。
1. `terraform init` : プラグインの初期化
2. `terraform plan` : 実行計画の確認(最重要! ここで何が起きるか震えるほど確認する)
3. `terraform apply` : 実行
—
3. 本題:保守性を破壊する「やってはいけない」モジュール設計5選
さて、ここからが本番です。Terraformの「モジュール」は、関連するリソースをひとまとめにして再利用するための仕組みです。しかし、設計を誤ると毒になります。
① 「神(God)モジュール」を作ってしまう
症状: `VPC` も `EC2` も `RDS` も `S3` も、すべて一つのモジュールに入っている。
なぜダメか: どこか一箇所を変更したいだけなのに、関係ないリソースまで再作成(Destroy & Create)されるリスクが高まります。
解決策: 「ネットワーク」「データベース」「アプリケーション」など、ライフサイクルが異なるものはモジュールを分けましょう。
② 過度な抽象化(なんでも変数化)
症状: モジュールの `variables.tf` が100行を超え、あらゆる設定が変数になっている。
なぜダメか: モジュールを呼び出す側で、結局すべての設定を書くことになります。これでは生のコードを書いているのと変わりません。
解決策: 「そのプロジェクトにおける標準値」をモジュール内にハードコードし、本当に変更が必要な数個だけを変数として公開しましょう。
③ 密結合なモジュール(リソースの依存)
症状: モジュールAの中で、モジュールBのリソースIDを直接参照している。
なぜダメか: Aを使うために必ずBが必要になり、単体でのテストができなくなります。
解決策: モジュールは「疎結合」に。必要な情報は `variable` で受け取り、作成した情報は `output` で渡す。これが「インターフェース設計」の極意です。
④ Outputを定義しない「ブラックボックス」
症状: リソースは作るが、そのIDやARNを `outputs.tf` で返さない。
なぜダメか: 後続のリソースが、その情報を使えなくなります。
解決策: 他のリソースが使いそうな値は、惜しみなく `output` に出してください。それがモジュールの「優しさ」です。
⑤ バージョン固定を忘れる
症状: モジュールのソースコードを `source = “./modules/vpc”` のように相対パスだけで管理し、バージョン管理していない。
なぜダメか: モジュール本体を修正した瞬間、それを使っている全環境に影響が出ます。
解決策: 共通モジュールは別リポジトリにし、`?ref=v1.0.0` のようにタグでバージョンを指定して呼び出しましょう。
—
4. 現場で震えるほど役立つ「クリーンなモジュール」の構造
これが、私が数々の修羅場をくぐり抜けて到達した、最も美しいモジュールの最小構成です。
modules/
└── simple_s3/
├── main.tf # リソースの定義本体
├── variables.tf # 入力(必要最小限に!)
├── outputs.tf # 出力(他で使いそうなものは全部出す)
└── versions.tf # 必要なTerraform/Providerのバージョンを記述
modules/simple_s3/main.tf の例:
resource “aws_s3_bucket” “this” {
bucket = var.bucket_name
# 現場の知恵:誤削除防止タグなどはモジュール側で強制する
tags = {
ManagedBy = “Terraform”
Module = “simple_s3”
}
}
サーバーサイド暗号化をデフォルトで有効にする(セキュリティの標準化)
resource “aws_s3_bucket_server_side_encryption_configuration” “this” {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = “AES256”
}
}
}
—
最後に:君へのメッセージ
Terraformのコードを書くとき、常に自分に問いかけてください。
「このコードは、1年後の自分が読んだときに意図が伝わるだろうか?」
インフラをコードにするということは、君の思考を資産にするということです。今日紹介したアンチパターンを避け、シンプルで美しい設計を心がければ、君のインフラは盤石なものになるでしょう。
もし迷ったら、いつでも聞いてください。コードは嘘をつきませんが、書いた人間の「迷い」は如実に現れます。自信を持って `apply` できる、そんなエンジニアへの第一歩を、今日ここから踏み出しましょう。
応援していますよ。