refactor-module
モノリシックなTerraform構成を、HashiCorpのモジュール設計原則とコミュニティのベストプラクティスに従い、再利用可能でメンテナンスしやすいモジュールへとリファクタリングします。
description の原文を見る
Transform monolithic Terraform configurations into reusable, maintainable modules following HashiCorp's module design principles and community best practices.
SKILL.md 本文
スキル: モジュールのリファクタリング
概要
このスキルは、モノリシック Terraform 構成を HashiCorp のモジュール設計原則とコミュニティベストプラクティスに従う再利用可能でメンテナンス性の高いモジュールに変換するプロセスで、AI エージェントをガイドします。
能力声明
エージェントは既存の Terraform コードを分析し、以下を含む適切に構造化されたモジュールに体系的にリファクタリングします:
- 明確なインターフェースコントラクト (変数と出力)
- 適切なカプセル化と抽象化
- バージョニングとドキュメント
- テストフレームワーク
- 既存の状態の移行パス
前提条件
- リファクタリング対象の既存 Terraform 構成
- リソースの依存関係の理解
- 現在の状態ファイルへのアクセス (移行計画用)
- モジュールレジストリパターンの知識
入力パラメータ
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
source_directory | string | はい | 既存 Terraform 構成へのパス |
module_name | string | はい | 新しいモジュールの名前 |
abstraction_level | string | いいえ | "simple", "intermediate", "advanced" (デフォルト: intermediate) |
preserve_state | boolean | はい | 状態の互換性を維持するかどうか |
target_registry | string | いいえ | ターゲットモジュールレジストリ (local, private, public) |
実行ステップ
1. 分析フェーズ
**リファクタリング候補の特定**
- 論理的機能ごとにリソースをグループ化
- 繰り返しパターンを特定
- リソース依存関係をマッピング
- 設定結合を検出
- 変数の使用パターンを分析
**複雑性の評価**
- リソース関係の数を計算
- 変数伝播の深さを測定
- リソース間の参照を特定
- 状態移行の複雑さを評価
2. モジュール設計
インターフェース設計
# 明確な入力コントラクトを定義
variable "network_config" {
description = "ネットワーク設定パラメータ"
type = object({
cidr_block = string
availability_zones = list(string)
enable_nat = bool
})
validation {
condition = can(cidrhost(var.network_config.cidr_block, 0))
error_message = "CIDR ブロックは有効な IPv4 CIDR である必要があります。"
}
}
# 出力コントラクトを定義
output "vpc_id" {
description = "作成された VPC の ID"
value = aws_vpc.main.id
}
output "private_subnet_ids" {
description = "プライベートサブネット ID のリスト"
value = { for k, v in aws_subnet.private : k => v.id }
}
カプセル化戦略
**モジュールに含めるもの:**
- 密結合されたリソース (VPC + サブネット)
- 共有ライフサイクルを持つリソース
- 明確な境界を持つ設定
**別々に保つもの:**
- 横断的関心事項 (監視、タグ付け)
- 異なるライフサイクルを持つリソース
- プロバイダー固有の構成
3. コード変換
変換前: モノリシック構成
# main.tf (モノリシック)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "production-vpc"
Environment = "prod"
}
}
resource "aws_subnet" "public_1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
tags = {
Name = "public-subnet-1"
Type = "public"
}
}
resource "aws_subnet" "public_2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "us-east-1b"
tags = {
Name = "public-subnet-2"
Type = "public"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "production-igw"
}
}
# ... より多くの繰り返しサブネットとルーティングリソース
変換後: モジュール構造
# modules/vpc/main.tf
locals {
subnet_count = length(var.availability_zones)
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
tags = merge(
var.tags,
{
Name = var.name
}
)
}
resource "aws_subnet" "public" {
for_each = var.create_public_subnets ? toset(var.availability_zones) : []
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.cidr_block, 8, index(var.availability_zones, each.value))
availability_zone = each.value
map_public_ip_on_launch = true
tags = merge(
var.tags,
{
Name = "${var.name}-public-${each.value}"
Type = "public"
}
)
}
resource "aws_internet_gateway" "main" {
count = var.create_public_subnets ? 1 : 0
vpc_id = aws_vpc.main.id
tags = merge(
var.tags,
{
Name = "${var.name}-igw"
}
)
}
# modules/vpc/variables.tf
variable "name" {
description = "すべてのリソースの名前プレフィックス"
type = string
}
variable "cidr_block" {
description = "VPC の CIDR ブロック"
type = string
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "有効な IPv4 CIDR ブロックである必要があります。"
}
}
variable "availability_zones" {
description = "アベイラビリティーゾーンのリスト"
type = list(string)
}
variable "create_public_subnets" {
description = "パブリックサブネットを作成するかどうか"
type = bool
default = true
}
variable "enable_dns_hostnames" {
description = "VPC で DNS ホスト名を有効にする"
type = bool
default = true
}
variable "enable_dns_support" {
description = "VPC で DNS サポートを有効にする"
type = bool
default = true
}
variable "tags" {
description = "すべてのリソースに適用するタグ"
type = map(string)
default = {}
}
# modules/vpc/outputs.tf
output "vpc_id" {
description = "VPC の ID"
value = aws_vpc.main.id
}
output "vpc_cidr_block" {
description = "VPC の CIDR ブロック"
value = aws_vpc.main.cidr_block
}
output "public_subnet_ids" {
description = "アベイラビリティーゾーンからパブリックサブネット ID へのマップ"
value = { for k, v in aws_subnet.public : k => v.id }
}
output "internet_gateway_id" {
description = "インターネットゲートウェイの ID"
value = try(aws_internet_gateway.main[0].id, null)
}
# モジュールを使用するルート構成
module "vpc" {
source = "./modules/vpc"
name = "production"
cidr_block = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
tags = {
Environment = "production"
ManagedBy = "Terraform"
}
}
4. 状態の移行
移行計画を生成
# migration.tf
# 状態のリファクタリングに moved ブロックを使用 (Terraform 1.1 以降)
moved {
from = aws_vpc.main
to = module.vpc.aws_vpc.main
}
moved {
from = aws_subnet.public_1
to = module.vpc.aws_subnet.public["us-east-1a"]
}
moved {
from = aws_subnet.public_2
to = module.vpc.aws_subnet.public["us-east-1b"]
}
moved {
from = aws_internet_gateway.main
to = module.vpc.aws_internet_gateway.main[0]
}
手動状態移行 (1.1 以前)
# 状態移行コマンドを生成
terraform state mv aws_vpc.main module.vpc.aws_vpc.main
terraform state mv aws_subnet.public_1 'module.vpc.aws_subnet.public["us-east-1a"]'
terraform state mv aws_subnet.public_2 'module.vpc.aws_subnet.public["us-east-1b"]'
terraform state mv aws_internet_gateway.main 'module.vpc.aws_internet_gateway.main[0]'
5. モジュールドキュメント
# VPC モジュール
## 概要
複数のアベイラビリティーゾーンにわたって、設定可能なパブリックサブネットとプライベートサブネットを持つ VPC を作成します。
## 機能
- マルチ AZ サブネットデプロイメント
- オプションの NAT ゲートウェイ構成
- VPC フロー ログ統合
- カスタマイズ可能な CIDR 割り当て
## 使用方法
\`\`\`hcl
module "vpc" {
source = "./modules/vpc"
name = "my-vpc"
cidr_block = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b"]
create_public_subnets = true
create_private_subnets = true
enable_nat_gateway = true
tags = {
Environment = "production"
}
}
\`\`\`
## 要件
| 名前 | バージョン |
|------|---------|
| terraform | >= 1.5.0 |
| aws | ~> 5.0 |
## 入力
| 名前 | 説明 | 型 | デフォルト | 必須 |
|------|------|------|---------|------|
| name | リソースの名前プレフィックス | `string` | n/a | はい |
| cidr_block | VPC CIDR ブロック | `string` | n/a | はい |
| availability_zones | AZ のリスト | `list(string)` | n/a | はい |
## 出力
| 名前 | 説明 |
|------|------|
| vpc_id | VPC 識別子 |
| public_subnet_ids | パブリックサブネット ID のマップ |
| private_subnet_ids | プライベートサブネット ID のマップ |
## 例
完全な使用例については、[examples/](./examples/) ディレクトリを参照してください。
6. テスト
terraform-test スキルを使用してください
テストファイル: テスト構成と実行ブロックを含む .tftest.hcl または .tftest.json ファイル。このファイルは Terraform 構成を検証します。
テストブロック: テスト全体の設定を定義するオプション構成ブロック (Terraform 1.6.0 以降で利用可能)。
実行ブロック: オプションの変数、プロバイダー構成、およびアサーションを含む単一のテストシナリオを定義します。各テストファイルには少なくとも 1 つの実行ブロックが必要です。
アサーションブロック: テストがパスするために true と評価される必要がある条件を含みます。失敗したアサーションはテストを失敗させます。
モックプロバイダー: 実際のインフラストラクチャを作成せずにプロバイダーの動作をシミュレートします (Terraform 1.7.0 以降で利用可能)。
テストモード: テストは apply モード (デフォルト、実際のインフラストラクチャを作成) または plan モード (リソースを作成せずにロジックを検証) で実行されます。
ファイル構造
Terraform テストファイルは .tftest.hcl または .tftest.json 拡張子を使用し、通常は tests/ ディレクトリに編成されています。ユニットテスト (plan モード) と統合テスト (apply モード - 実際のリソースを作成) を区別するために、明確な命名規則を使用してください:
my-module/
├── main.tf
├── variables.tf
├── outputs.tf
└── tests/
├── unit_test.tftest.hcl # ユニットテスト (plan モード)
└── integration_test.tftest.hcl # 統合テスト (apply モード - 実際のリソースを作成)
リファクタリングパターン
パターン 1: リソースグループ化
関連リソースを凝集的なモジュールに抽出します:
- ネットワーク (VPC、サブネット、ルートテーブル)
- コンピューティング (ASG、起動テンプレート、ロードバランサー)
- データ (RDS、ElastiCache、S3)
パターン 2: 設定レイヤーリング
# デフォルトを持つベースモジュール
module "vpc_base" {
source = "./modules/vpc-base"
# 最小限の必須入力
}
# 環境固有のラッパー
module "vpc_prod" {
source = "./modules/vpc-production"
# ベースから継承し、本番環境固有の構成を追加
}
パターン 3: コンポジション
# 小さくてフォーカスされたモジュール
module "vpc" {
source = "./modules/vpc"
}
module "security_groups" {
source = "./modules/security-groups"
vpc_id = module.vpc.vpc_id
}
module "application" {
source = "./modules/application"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
sg_ids = module.security_groups.app_sg_ids
}
一般的な落とし穴
1. 過度な抽象化
# ❌ 過度に汎用的なモジュールを作成しない
variable "resources" {
type = map(map(any)) # 柔軟すぎて、検証が難しい
}
# ✅ 特定の型を持つインターフェースを使用
variable "database_config" {
type = object({
engine = string
instance_class = string
})
}
2. 密結合
# ❌ 直接参照によってモジュールを密結合しない
# モジュール A
output "instance_id" { value = aws_instance.app.id }
# モジュール B (同じ構成内)
resource "aws_eip" "app" {
instance = module.a.instance_id # 密結合
}
# ✅ ルートモジュールを通じて依存関係を渡す
module "compute" {
source = "./modules/compute"
}
resource "aws_eip" "app" {
instance = module.compute.instance_id
}
3. 状態移行エラー
常に非本番環境で移行をテストしてください:
# 移行後に変更がないことを確認するプランを作成
terraform plan -out=migration.tfplan
# 注意深く確認
terraform show migration.tfplan
# プランが変更を示さない場合のみ適用
terraform apply migration.tfplan
バージョン管理戦略
# モジュールにセマンティックバージョニングを使用
module "vpc" {
source = "git::https://github.com/org/terraform-modules.git//vpc?ref=v1.2.0"
version = "~> 1.2"
}
# 本番環境で特定のバージョンに固定
# 開発環境でバージョン範囲を使用
成功基準
- モジュールは単一の明確に定義された責務を持つ
- すべての変数に説明と型がある
- 検証ルールが無効な構成を防ぐ
- 出力はコンシューマーに十分な情報を提供する
- ドキュメントに使用例が含まれている
- テストがモジュール動作を検証する
- 状態移行がリソースの再作成なしに完了した
- リファクタリング後にプランの差分がない
関連スキル
- Terraform コード生成 - 新しい Terraform モジュールのスタイルガイド
- Azure Verified Modules - Azure 推奨モジュール仕様
リソース
リビジョン履歴
| バージョン | 日付 | 変更 |
|---|---|---|
| 1.0.0 | 2025-11-07 | 初期スキル定義 |
ライセンス: MPL-2.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- hashicorp
- ライセンス
- MPL-2.0
- 最終更新
- 不明
Source: https://github.com/hashicorp/agent-skills / ライセンス: MPL-2.0
関連スキル
superpowers-streamer-cli
SuperPowers デスクトップストリーマーの npm パッケージをインストール、ログイン、実行、トラブルシューティングできます。ユーザーが npm から `superpowers-ai` をセットアップしたい場合、メールまたは電話でサインインもしくはアカウント作成を行いたい場合、ストリーマーを起動したい場合、表示されたコントロールリンクを開きたい場合、後で停止したい場合、またはソースコードへのアクセスなしに npm やランタイムの一般的な問題から復旧したい場合に使用します。
catc-client-ops
Catalyst Centerのクライアント操作・監視機能 - 有線・無線クライアントのリスト表示・フィルタリング、MACアドレスによる詳細なクライアント検索、クライアント数分析、時間軸での分析、SSIDおよび周波数帯によるフィルタリング、無線トラブルシューティング機能を提供します。MACアドレスやIPアドレスでのクライアント検索、サイト別やSSID別のクライアント数集計、無線周波数帯の分布分析、Wi-Fi信号の問題調査が必要な場合に活用できます。
ci-cd-and-automation
CI/CDパイプラインの設定を自動化します。ビルドおよびデプロイメントパイプラインの構築または変更時に使用できます。品質ゲートの自動化、CI内のテストランナー設定、またはデプロイメント戦略の確立が必要な場合に活用します。
shipping-and-launch
本番環境へのリリース準備を行います。本番環境へのデプロイ準備が必要な場合、リリース前チェックリストが必要な場合、監視機能の設定を行う場合、段階的なロールアウトを計画する場合、またはロールバック戦略が必要な場合に使用します。
linear-release-setup
Linear Releaseに向けたCI/CD設定を生成します。リリース追跡の設定、LinearのCIパイプライン構築、またはLinearリリースとのデプロイメント連携を実施する際に利用できます。GitHub Actions、GitLab CI、CircleCIなど複数のプラットフォームに対応しています。
tracking-application-response-times
API エンドポイント、データベースクエリ、サービスコール全体にわたるアプリケーションのレスポンスタイムを追跡・最適化できます。パフォーマンス監視やボトルネック特定の際に活用してください。「レスポンスタイムを追跡する」「API パフォーマンスを監視する」「遅延を分析する」といった表現で呼び出せます。