Terraform 模块化结构设计

Terraform 模块化结构设计

Deng YongJie's blog 22 2025-05-25

Terraform 模块化结构设计

Terraform 多环境管理,建议采用以下结构:

project-root/
├── components/          # 模組目錄
│   ├── 01-preserver/  # Terraform後端S3資源模組
│   │   ├── outputs.tf
│   │   ├── s3.tf
│   │   └── variables.tf  
│   │   
│   └── 02-network/    # 網路模組(如 VPC、Subnet)
│       ├── vpc.tf
│       ├── eip.tf
│       ├── subnet.tf
│       ├── security_group.tf
│       ├── nacl.tf
│       ├── nat_gw.tf
│       ├── igw.tf
│       ├── rtb.tf
│       ├── variables.tf
│       └── outputs.tf
│
├── environments/        # 環境變數目錄(與 components 同級)
│   ├── dev/             # 開發環境
│   │   ├── 01-preserver.tfvars
│   │   └── 02-network.tfvars
│   ├── uat/             # 預發佈環境
│   │   ├── 01-preserver.tfvars
│   │   └── 02-network.tfvars
│   └── prd/             # 生產環境
│       ├── 01-preserver.tfvars
│       └── 02-network.tfvars
│
├── versions.tf          # 版本約束
└── scripts/             # 统一的脚本目录(如 apply、plan 等)
    ├── tf-apply.sh
    ├── tf-plan.sh
    ├── tf-init.sh
    └── tf-destroy.sh

模块设计原则

components/03-eks-cluster/
├── eks.tf                 # 定义 EKS 资源
├── variables.tf           # 模块输入变量定义
└── outputs.tf             # 模块输出变量定义

环境隔离与变量管理

environments/dev/ 中,为每个模块创建独立的 .tfvars 文件:

aws_region = "ap-east-1"

# VPC配置,定義VPC的CIDR和名稱
vpc_config = {
  cidr_block = "10.x.x.0/16"
  name       = "vpc-dev"
}

后端配置与版本统一

tf-init.sh 初始化自动判断,自动生成对应模块独立状态文件的后端配置
image-1747363518993
image-1747363561928

(1) 模块化与复用性

  • 独立性:每个模块(如 03-eks-cluster)可独立部署和更新。
  • 复用性:每个模块(如 03-eks-cluster)可在多个组件中复用。

(2) 环境隔离

  • 变量隔离:通过 .tfvars 文件实现环境特定配置。
  • 状态隔离:通过 S3 后端和工作区确保环境状态独立。

(3) 可维护性

  • 清晰的结构:模块、环境、共享配置分层清晰。
  • 依赖明确:通过输出变量或远程状态引用其他模块的输出。

如何解决首次创建后端存储的依赖问题:

  • 当使用 terraform init -backend=false 时,Terraform 会禁用远程后端(如 S3),转而使用本地 terraform.tfstate 文件存储状态。
  • 如果 S3 存储桶本身是通过 Terraform 模块(如 01-preserver)创建的,那么在初始化时 S3 后端可能还不存在,导致无法直接写入状态文件。
  • 因此,必须先在本地应用配置(apply),创建 S3 存储桶,再将本地状态文件 terraform.tfstate 手动推送到新创建的 S3 存储桶中。

避免循环依赖:

  • 如果直接启用 S3 后端(-backend=true),Terraform 会尝试在初始化时验证 S3 存储桶是否存在。但存储桶本身可能由当前模块创建,导致初始化失败(因为存储桶还未创建)。
  • 手动推送状态是解决这种 “先有鸡还是先有蛋” 问题的临时方案。

image-1747368380772