三层 Terraform 架构

发布: (2025年12月6日 GMT+8 09:25)
7 min read
原文: Dev.to

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-backenddynamodb-backendkms-backendvpc-basic
基础设施模块(外观)将相关资源打包为可复用单元infra/remote-backend(S3 + DynamoDB + KMS),infra/vpc(VPC + 子网)
组合层环境‑特定的入口点(区域 + 环境)composition/remote-backend/us-east-2/prodcomposition/vpc/us-east-2/prod

这与课程中提出的 “resource → infra → composition” 模式相呼应,但代码更简洁、易读,适合教学和实际项目使用。

Back to Blog

相关文章

阅读更多 »