Terraform模块:代码复用与组织
Terraform模块:代码复用与组织
什么是Terraform模块
模块是Terraform中实现代码复用的基本单元。它是一组资源和配置的集合,可以被多个项目重复使用。模块化设计能提高代码的可维护性、可测试性和可复用性。
创建模块
模块目录结构
modules/
├── vpc/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ └── versions.tf
├── ec2/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ └── versions.tf
└── rds/
├── main.tf
├── variables.tf
├── outputs.tf
└── versions.tf
VPC模块示例
# modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, {
Name = "${var.project_name}-vpc"
})
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.this.id
cidr_block = var.public_subnets[count.index].cidr
availability_zone = var.public_subnets[count.index].az
map_public_ip_on_launch = true
tags = merge(var.tags, {
Name = "${var.project_name}-public-${count.index + 1}"
})
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.this.id
cidr_block = var.private_subnets[count.index].cidr
availability_zone = var.private_subnets[count.index].az
tags = merge(var.tags, {
Name = "${var.project_name}-private-${count.index + 1}"
})
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
tags = merge(var.tags, {
Name = "${var.project_name}-igw"
})
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.this.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
tags = merge(var.tags, {
Name = "${var.project_name}-public-rt"
})
}
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# modules/vpc/variables.tf
variable "project_name" {
description = "项目名称"
type = string
}
variable "cidr_block" {
description = "VPC CIDR块"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "必须是有效的CIDR块"
}
}
variable "public_subnets" {
description = "公有子网配置"
type = list(object({
cidr = string
az = string
}))
}
variable "private_subnets" {
description = "私有子网配置"
type = list(object({
cidr = string
az = string
}))
}
variable "tags" {
description = "资源标签"
type = map(string)
default = {}
}
# modules/vpc/outputs.tf
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.this.id
}
output "vpc_cidr" {
description = "VPC CIDR块"
value = aws_vpc.this.cidr_block
}
output "public_subnet_ids" {
description = "公有子网ID列表"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "私有子网ID列表"
value = aws_subnet.private[*].id
}
output "internet_gateway_id" {
description = "互联网网关ID"
value = aws_internet_gateway.this.id
}
使用模块
本地模块
# main.tf
module "vpc" {
source = "./modules/vpc"
project_name = "my-app"
cidr_block = "10.0.0.0/16"
public_subnets = [
{ cidr = "10.0.1.0/24", az = "us-west-2a" },
{ cidr = "10.0.2.0/24", az = "us-west-2b" },
]
private_subnets = [
{ cidr = "10.0.10.0/24", az = "us-west-2a" },
{ cidr = "10.0.11.0/24", az = "us-west-2b" },
]
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
module "ec2" {
source = "./modules/ec2"
instance_count = 2
instance_type = "t3.micro"
subnet_ids = module.vpc.private_subnet_ids
vpc_id = module.vpc.vpc_id
}
远程模块
# 使用Git仓库
module "vpc" {
source = "git::https://github.com/company/terraform-modules.git//vpc?ref=v1.2.0"
# 模块参数...
}
# 使用Terraform Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}
S3模块存储
# 使用S3存储模块
module "vpc" {
source = "s3::https://bucket-name.s3.amazonaws.com/modules/vpc.zip"
# 模块参数...
}
模块版本管理
版本约束
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0" # 兼容5.x版本
# 或精确版本
# version = "= 5.0.0"
# 或版本范围
# version = ">= 5.0, < 6.0"
}
版本锁定
# 更新模块到最新版本
terraform get -update
# 锁定模块版本
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64
模块测试
测试文件结构
modules/vpc/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
└── tests/
├── main_test.go
└── terraform_test.go
使用Terratest
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestVpcModule(t *testing.T) {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../",
Vars: map[string]interface{}{
"project_name": "test-vpc",
"cidr_block": "10.0.0.0/16",
"public_subnets": []map[string]string{
{"cidr": "10.0.1.0/24", "az": "us-west-2a"},
},
"private_subnets": []map[string]string{
{"cidr": "10.0.10.0/24", "az": "us-west-2a"},
},
},
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
vpcId := terraform.Output(t, terraformOptions, "vpc_id")
assert.Regexp(t, "^vpc-", vpcId)
publicSubnetIds := terraform.OutputList(t, terraformOptions, "public_subnet_ids")
assert.Equal(t, 1, len(publicSubnetIds))
}
模块发布
发布到Terraform Registry
# 1. 创建GitHub仓库
git init
git add .
git commit -m "Initial module"
# 2. 打版本标签
git tag v1.0.0
git push origin v1.0.0
# 3. 在Terraform Registry中连接仓库
# 访问 https://app.terraform.io/ 托管注册表
# 或使用公共注册表 https://registry.terraform.io/
模块文档
# VPC Module
## Description
创建标准VPC配置,包括公有/私有子网、互联网网关和路由表。
## Usage
\```hcl
module "vpc" {
source = "company/vpc/aws"
version = "1.0.0"
project_name = "my-app"
cidr_block = "10.0.0.0/16"
}
\```
## Inputs
| Name | Description | Type | Default |
|------|-------------|------|---------|
| project_name | 项目名称 | string | - |
| cidr_block | VPC CIDR块 | string | "10.0.0.0/16" |
## Outputs
| Name | Description |
|------|-------------|
| vpc_id | VPC ID |
| public_subnet_ids | 公有子网ID列表 |
最佳实践
- 单一职责:每个模块专注于一个功能
- 清晰接口:定义明确的输入输出
- 版本管理:使用语义化版本控制
- 完整文档:提供使用示例和输入输出说明
- 自动化测试:编写单元测试和集成测试