三层 Terraform 架构
Source: Dev.to
前置条件
- Terraform ≥ 1.0
- 具备创建 S3 存储桶、DynamoDB 表、KMS 密钥、VPC、子网、Internet Gateway(IGW)和路由表权限的 AWS 凭证。
文件夹结构
在项目根目录下创建如下目录布局:
terraform-3layer-aws/
├── composition/
│ ├── remote-backend/
│ │ └── us-east-2/
│ │ └── prod/
│ └── vpc/
│ └── us-east-2/
│ └── prod/
├── infra/
│ ├── remote-backend/
│ └── vpc/
└── resource-modules/
├── storage/
│ └── s3-backend/
├── dynamodb/
│ └── backend/
├── kms/
│ └── backend/
└── vpc/
└── basic/
资源模块(最低层)
2.1 S3 后端存储桶模块
Path: resource-modules/storage/s3-backend/main.tf
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
force_destroy = var.force_destroy
tags = var.tags
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = var.kms_key_arn
}
}
}
resource "aws_s3_bucket_public_access_block" "this" {
bucket = aws_s3_bucket.this.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
variable "bucket_name" { type = string }
variable "force_destroy" { type = bool }
variable "kms_key_arn" { type = string }
variable "tags" { type = map(string) }
output "bucket_name" { value = aws_s3_bucket.this.id }
output "bucket_arn" { value = aws_s3_bucket.this.arn }
2.2 DynamoDB 后端表模块
Path: resource-modules/dynamodb/backend/main.tf
resource "aws_dynamodb_table" "this" {
name = var.table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = var.tags
}
variable "table_name" { type = string }
variable "tags" { type = map(string) }
output "table_name" { value = aws_dynamodb_table.this.name }
output "table_arn" { value = aws_dynamodb_table.this.arn }
2.3 KMS 密钥模块
Path: resource-modules/kms/backend/main.tf
resource "aws_kms_key" "this" {
description = var.description
deletion_window_in_days = 10
enable_key_rotation = true
tags = var.tags
}
variable "description" { type = string }
variable "tags" { type = map(string) }
output "key_id" { value = aws_kms_key.this.id }
output "key_arn" { value = aws_kms_key.this.arn }
2.4 基础 VPC 模块
Path: resource-modules/vpc/basic/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
tags = merge(var.tags, { Name = "${var.project}-${var.environment}-vpc" })
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
tags = var.tags
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.this.id
cidr_block = var.public_subnet_cidr
map_public_ip_on_launch = true
availability_zone = var.az
tags = var.tags
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.this.id
cidr_block = var.private_subnet_cidr
availability_zone = var.az
tags = var.tags
}
resource "aws_subnet" "database" {
vpc_id = aws_vpc.this.id
cidr_block = var.database_subnet_cidr
availability_zone = var.az
tags = var.tags
}
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 = var.tags
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
variable "project" { type = string }
variable "environment" { type = string }
variable "cidr_block" { type = string }
variable "az" { type = string }
variable "public_subnet_cidr" { type = string }
variable "private_subnet_cidr" { type = string }
variable "database_subnet_cidr" { type = string }
variable "tags" { type = map(string) }
output "vpc_id" { value = aws_vpc.this.id }
output "public_subnet_id" { value = aws_subnet.public.id }
output "private_subnet_id" { value = aws_subnet.private.id }
output "database_subnet_id" { value = aws_subnet.database.id }
基础设施层 – 远程后端外观
此层将三个后端相关的资源模块打包,并提供单一、简洁的接口。
Path: infra/remote-backend/variables.tf
variable "project" { type = string }
variable "environment"{ type = string }
variable "region" { type = string }
resource "random_integer" "suffix" {
min = 1000
max = 9999
}
module "kms_backend" {
source = "../../resource-modules/kms/backend"
description = "${var.project}-${var.environment} backend key"
tags = {
Project = var.project
Environment = var.environment
}
}
module "s3_backend" {
source = "../../resource-modules/storage/s3-backend"
bucket_name = "${var.project}-${var.environment}-${random_integer.suffix.result}"
force_destroy = true
kms_key_arn = module.kms_backend.key_arn
tags = {
Project = var.project
Environment = var.environment
}
}
module "dynamodb_backend" {
source = "../../resource-modules/dynamodb/backend"
table_name = "${var.project}-${var.environment}-lock"
tags = {
Project = var.project
Environment = var.environment
}
}
output "backend_bucket_name" { value = module.s3_backend.bucket_name }
output "backend_dynamodb_table_name" { value = module.dynamodb_backend.table_name }
output "backend_kms_key_arn" { value = module.kms_backend.key_arn }
组合 – 远程后端 (us-east-2 / prod)
在特定区域/环境下创建远程后端的入口点。
Path: composition/remote-backend/us-east-2/prod/main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# IMPORTANT: keep backend local for the first run.
# After the bucket & table exist, uncomment the block below.
# backend "s3" {
# bucket = ""
# key = "terraform.tfstate"
# region = "us-east-2"
# dynamodb_table = ""
# encrypt = true
# }
}
provider "aws" {
region = var.region
}
module "remote_backend" {
source = "../../../infra/remote-backend"
project = var.project
environment = var.environment
region = var.region
}
output "backend_bucket_name" { value = module.remote_backend.backend_bucket_name }
output "backend_dynamodb_table_name" { value = module.remote_backend.backend_dynamodb_table_name }
output "backend_kms_key_arn" { value = module.remote_backend.backend_kms_key_arn }
variable "project" { type = string }
variable "environment"{ type = string }
variable "region" { type = string }
# Example values
# project = "my-demo"
# environment= "prod"
# region = "us-east-2"
运行远程后端堆栈
cd composition/remote-backend/us-east-2/prod
terraform init
terraform apply
在存储桶和 DynamoDB 表创建完成后,你可以在其他堆栈中配置使用该远程后端:
backend "s3" {
bucket = ""
key = "path/to/terraform.tfstate"
region = "us-east-2"
dynamodb_table = ""
encrypt = true
}
基础设施 – VPC 外观
包装基础 VPC 资源模块。
Path: infra/vpc/locals.tf
variable "project" { type = string }
variable "cidr_block" { type = string }
variable "public_subnet_cidr" { type = string }
variable "private_subnet_cidr" { type = string }
variable "database_subnet_cidr" { type = string }
variable "az" { type = string }
variable "tags" { type = map(string) }
module "vpc_basic" {
source = "../../resource-modules/vpc/basic"
project = var.project
environment = var.environment
cidr_block = var.cidr_block
az = var.az
public_subnet_cidr = var.public_subnet_cidr
private_subnet_cidr = var.private_subnet_cidr
database_subnet_cidr = var.database_subnet_cidr
tags = var.tags
}
output "vpc_id" { value = module.vpc_basic.vpc_id }
output "public_subnet_id" { value = module.vpc_basic.public_subnet_id }
output "private_subnet_id" { value = module.vpc_basic.private_subnet_id }
output "database_subnet_id" { value = module.vpc_basic.database_subnet_id }
组合 – VPC (us-east-2 / prod)
使用基础设施外观创建 VPC。
Path: composition/vpc/us-east-2/prod/main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# OPTIONAL: after the remote backend exists, configure it here.
# backend "s3" { ... }
}
provider "aws" {
region = var.region
}
module "vpc" {
source = "../../../infra/vpc"
project = var.project
environment = var.environment
region = var.region
cidr_block = var.cidr_block
az = var.az
public_subnet_cidr = var.public_subnet_cidr
private_subnet_cidr = var.private_subnet_cidr
database_subnet_cidr= var.database_subnet_cidr
tags = {
Project = var.project
Environment = var.environment
}
}
output "vpc_id" { value = module.vpc.vpc_id }
output "public_subnet_id" { value = module.vpc.public_subnet_id }
output "private_subnet_id" { value = module.vpc.private_subnet_id }
output "database_subnet_id" { value = module.vpc.database_subnet_id }
variable "project" { type = string }
variable "environment" { type = string }
variable "region" { type = string }
variable "cidr_block" { type = string }
variable "az" { type = string }
variable "public_subnet_cidr" { type = string }
variable "private_subnet_cidr" { type = string }
variable "database_subnet_cidr" { type = string }
# Example values
# project = "my-demo"
# environment = "prod"
# region = "us-east-2"
# cidr_block = "10.0.0.0/16"
# az = "us-east-2a"
# public_subnet_cidr = "10.0.1.0/24"
# private_subnet_cidr = "10.0.2.0/24"
# database_subnet_cidr = "10.0.3.0/24"
运行 VPC 堆栈
cd composition/vpc/us-east-2/prod
terraform init
terraform apply
这如何匹配 3‑层架构
| 层级 | 目的 | 示例模块 |
|---|---|---|
| 资源模块 | 原始 AWS 资源,无环境逻辑 | s3-backend、dynamodb-backend、kms-backend、vpc-basic |
| 基础设施模块(外观) | 将相关资源打包为可复用单元 | infra/remote-backend(S3 + DynamoDB + KMS),infra/vpc(VPC + 子网) |
| 组合层 | 环境‑特定的入口点(区域 + 环境) | composition/remote-backend/us-east-2/prod、composition/vpc/us-east-2/prod |
这与课程中提出的 “resource → infra → composition” 模式相呼应,但代码更简洁、易读,适合教学和实际项目使用。