Terraform 模块最佳实践 #

模块设计原则 #

1. 单一职责原则 #

每个模块应该只负责一种类型的基础设施资源。

text
┌─────────────────────────────────────────────────────────────┐
│                    单一职责示例                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  好的设计:                                                 │
│  modules/                                                   │
│  ├── vpc/              只负责 VPC                          │
│  ├── subnet/           只负责子网                          │
│  ├── security-group/   只负责安全组                        │
│  └── ec2-instance/     只负责 EC2 实例                     │
│                                                             │
│  不好的设计:                                               │
│  modules/                                                   │
│  └── infrastructure/   包含所有资源                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. 可组合性 #

模块应该设计为可以轻松组合使用。

hcl
module "vpc" {
  source = "./modules/vpc"
}

module "subnet" {
  source = "./modules/subnet"
  
  vpc_id = module.vpc.id
}

module "security_group" {
  source = "./modules/security-group"
  
  vpc_id = module.vpc.id
}

module "ec2" {
  source = "./modules/ec2"
  
  subnet_id         = module.subnet.id
  security_group_id = module.security_group.id
}

3. 可重用性 #

模块应该设计为可以在不同项目中重用。

hcl
module "vpc_dev" {
  source = "./modules/vpc"
  
  environment = "dev"
  cidr_block  = "10.0.0.0/16"
}

module "vpc_prod" {
  source = "./modules/vpc"
  
  environment = "prod"
  cidr_block  = "10.1.0.0/16"
}

4. 可测试性 #

模块应该易于测试。

hcl
variable "create_resources" {
  description = "Whether to create resources"
  type        = bool
  default     = true
}

resource "aws_vpc" "main" {
  count = var.create_resources ? 1 : 0
  
  cidr_block = var.cidr_block
}

模块结构 #

标准结构 #

text
modules/
└── vpc/
    ├── main.tf          主要资源配置
    ├── variables.tf     输入变量定义
    ├── outputs.tf       输出值定义
    ├── versions.tf      版本约束
    ├── providers.tf     Provider 配置(可选)
    ├── locals.tf        本地值(可选)
    ├── data.tf          数据源(可选)
    ├── README.md        模块文档
    ├── LICENSE          许可证
    └── examples/        示例
        ├── basic/
        │   ├── main.tf
        │   └── outputs.tf
        └── complete/
            ├── main.tf
            └── outputs.tf

文件组织 #

text
┌─────────────────────────────────────────────────────────────┐
│                    文件组织原则                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  main.tf        主要资源配置                                │
│  variables.tf   所有输入变量                                │
│  outputs.tf     所有输出值                                  │
│  versions.tf    Terraform 和 Provider 版本约束              │
│  providers.tf   Provider 配置(如果需要)                   │
│  locals.tf      本地值(如果较多)                          │
│  data.tf        数据源(如果较多)                          │
│  README.md      模块文档                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

命名规范 #

模块命名 #

text
┌─────────────────────────────────────────────────────────────┐
│                    模块命名规范                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  使用小写字母和连字符:                                     │
│  ✅ vpc                                                    │
│  ✅ security-group                                          │
│  ✅ ec2-instance                                            │
│  ✅ rds-mysql                                               │
│                                                             │
│  避免使用:                                                 │
│  ❌ vpcModule                                              │
│  ❌ SecurityGroup                                           │
│  ❌ ec2_instance                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

变量命名 #

hcl
variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string
}

variable "availability_zones" {
  description = "List of availability zones"
  type        = list(string)
}

variable "enable_dns_hostnames" {
  description = "Enable DNS hostnames in the VPC"
  type        = bool
  default     = true
}

variable "tags" {
  description = "Tags to apply to all resources"
  type        = map(string)
  default     = {}
}

输出命名 #

hcl
output "vpc_id" {
  description = "The ID of the VPC"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "List of public subnet IDs"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "List of private subnet IDs"
  value       = aws_subnet.private[*].id
}

输入变量设计 #

必需变量 #

hcl
variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string
  
  validation {
    condition     = can(cidrhost(var.vpc_cidr, 0))
    error_message = "Must be a valid CIDR block."
  }
}

可选变量 #

hcl
variable "enable_dns_hostnames" {
  description = "Enable DNS hostnames in the VPC"
  type        = bool
  default     = true
}

variable "tags" {
  description = "Tags to apply to all resources"
  type        = map(string)
  default     = {}
}

复杂类型变量 #

hcl
variable "subnets" {
  description = "Map of subnet configurations"
  type = map(object({
    cidr_block              = string
    availability_zone       = string
    map_public_ip_on_launch = optional(bool, false)
  }))
  default = {}
}

variable "vpc_config" {
  description = "VPC configuration"
  type = object({
    cidr_block           = string
    enable_dns_hostnames = optional(bool, true)
    enable_dns_support   = optional(bool, true)
    instance_tenancy     = optional(string, "default")
  })
}

变量验证 #

hcl
variable "environment" {
  description = "Environment name"
  type        = string
  
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  
  validation {
    condition     = can(regex("^t[23]\\.(micro|small|medium|large)$", var.instance_type))
    error_message = "Instance type must be t2 or t3 family (micro, small, medium, or large)."
  }
}

输出值设计 #

输出所有重要属性 #

hcl
output "vpc_id" {
  description = "The ID of the VPC"
  value       = aws_vpc.main.id
}

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

output "vpc_arn" {
  description = "The ARN of the VPC"
  value       = aws_vpc.main.arn
}

output "public_subnet_ids" {
  description = "List of public subnet IDs"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "List of private subnet IDs"
  value       = aws_subnet.private[*].id
}

使用对象输出 #

hcl
output "vpc" {
  description = "VPC information"
  value = {
    id         = aws_vpc.main.id
    cidr_block = aws_vpc.main.cidr_block
    arn        = aws_vpc.main.arn
  }
}

output "subnets" {
  description = "Subnet information"
  value = {
    public  = aws_subnet.public[*].id
    private = aws_subnet.private[*].id
  }
}

版本管理 #

语义化版本 #

text
┌─────────────────────────────────────────────────────────────┐
│                    语义化版本                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  MAJOR.MINOR.PATCH                                         │
│                                                             │
│  MAJOR - 不兼容的 API 变更                                  │
│  MINOR - 向后兼容的功能新增                                 │
│  PATCH - 向后兼容的问题修复                                 │
│                                                             │
│  示例:                                                    │
│  1.0.0 - 初始版本                                          │
│  1.1.0 - 新增功能                                          │
│  1.1.1 - Bug 修复                                          │
│  2.0.0 - 破坏性变更                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

版本约束 #

hcl
terraform {
  required_version = ">= 1.0.0"
  
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.0.0, < 6.0.0"
    }
  }
}

Git 标签 #

bash
git tag v1.0.0
git push origin v1.0.0
hcl
module "vpc" {
  source = "github.com/myorg/terraform-modules//vpc?ref=v1.0.0"
}

文档 #

README.md #

markdown
# VPC Module

## Description

This module creates a VPC with public and private subnets, NAT gateways, and related networking resources.

## Usage

### Basic Example

```hcl
module "vpc" {
  source = "./modules/vpc"
  
  vpc_cidr = "10.0.0.0/16"
}

Complete Example #

hcl
module "vpc" {
  source = "./modules/vpc"
  
  vpc_cidr             = "10.0.0.0/16"
  availability_zones   = ["us-east-1a", "us-east-1b"]
  public_subnet_cidrs  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnet_cidrs = ["10.0.11.0/24", "10.0.12.0/24"]
  
  enable_nat_gateway = true
  single_nat_gateway = true
  
  tags = {
    Environment = "production"
  }
}

Requirements #

Name Version
terraform >= 1.0.0
aws >= 4.0.0

Providers #

Name Version
aws >= 4.0.0

Inputs #

Name Description Type Default Required
vpc_cidr CIDR block for the VPC string n/a yes
availability_zones List of availability zones list(string) n/a yes
tags Tags to apply to all resources map(string) {} no

Outputs #

Name Description
vpc_id The ID of the VPC
public_subnet_ids List of public subnet IDs
private_subnet_ids List of private subnet IDs
text

## 测试

### 基本验证

```bash
terraform init
terraform validate
terraform fmt -check
terraform plan

Terratest #

go
package test

import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/terraform"
    "github.com/stretchr/testify/assert"
)

func TestVPCModule(t *testing.T) {
    t.Parallel()
    
    terraformOptions := &terraform.Options{
        TerraformDir: "../examples/basic",
        Vars: map[string]interface{}{
            "vpc_cidr": "10.0.0.0/16",
        },
    }
    
    defer terraform.Destroy(t, terraformOptions)
    
    terraform.InitAndApply(t, terraformOptions)
    
    vpcId := terraform.Output(t, terraformOptions, "vpc_id")
    assert.NotEmpty(t, vpcId)
}

最佳实践清单 #

text
┌─────────────────────────────────────────────────────────────┐
│                    最佳实践清单                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  设计:                                                    │
│  □ 单一职责原则                                            │
│  □ 可组合性                                                │
│  □ 可重用性                                                │
│  □ 可测试性                                                │
│                                                             │
│  结构:                                                    │
│  □ 标准文件结构                                            │
│  □ 清晰的文件组织                                          │
│  □ 完整的示例                                              │
│                                                             │
│  命名:                                                    │
│  □ 一致的命名规范                                          │
│  □ 描述性的名称                                            │
│  □ 避免缩写                                                │
│                                                             │
│  变量:                                                    │
│  □ 必需变量无默认值                                        │
│  □ 可选变量有默认值                                        │
│  □ 变量验证                                                │
│  □ 描述文档                                                │
│                                                             │
│  输出:                                                    │
│  □ 输出所有重要属性                                        │
│  □ 添加描述                                                │
│  □ 敏感输出标记                                            │
│                                                             │
│  文档:                                                    │
│  □ README.md                                               │
│  □ 使用示例                                                │
│  □ 输入输出说明                                            │
│                                                             │
│  版本:                                                    │
│  □ 语义化版本                                              │
│  □ 版本约束                                                │
│  □ CHANGELOG                                               │
│                                                             │
│  测试:                                                    │
│  □ terraform validate                                      │
│  □ terraform plan                                          │
│  □ 自动化测试                                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

掌握了模块最佳实践后,接下来学习 内置函数,了解 Terraform 提供的强大函数库!

最后更新:2026-03-29