研发协作
单体 Terraform 配置需要重构为可复用模块时…
当你需要把已有的单体 Terraform 配置拆成可复用、可维护模块,并安全迁移现有 state 时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
单体 Terraform 配置需要重构为特定
解决思路
- 分析现有 Terraform 代码,识别重构候选:按逻辑功能对资源分组。
- 分析现有 Terraform 代码,识别重构候选:识别重复出现的模式。
- 分析现有 Terraform 代码,识别重构候选:映射资源之间的依赖关系。
- 分析现有 Terraform 代码,识别重构候选:检测配置耦合。
- 分析现有 Terraform 代码,识别重构候选:分析变量使用模式。
- 进行复杂度评估:统计资源关系数量。
- 进行复杂度评估:衡量变量传播深度。
- 进行复杂度评估:识别跨资源引用。
- 进行复杂度评估:评估状态迁移复杂度。
- 模块设计:定义清晰的输入契约,使用 variable 声明变量,包含 description、type,并用 validation 块做校验。
- 模块设计:定义清晰的输出契约,使用 output 声明输出,包含 description 和 value。
- 封装策略:把紧耦合资源(如 VPC 与子网)放入同一模块。
- 封装策略:把共享生命周期的资源放入同一模块。
- 封装策略:把边界清晰的配置放入同一模块。
- 封装策略:将横切关注点(如监控、标签)保持分离。
- 封装策略:将生命周期不同的资源保持分离。
- 封装策略:将提供商特定配置保持分离。
- 代码转换:把单体配置中的常量提取为模块变量,如 cidr_block、availability_zones、enable_dns_hostnames 等。
- 代码转换:在模块中使用 locals 计算衍生值(如 subnet_count = length(var.availability_zones))。
- 代码转换:使用 for_each 基于 availability_zones 创建重复资源(如 public 子网),并按条件决定是否创建。
- 代码转换:使用 cidrsubnet 根据 VPC CIDR 和索引动态计算子网 CIDR。
- 代码转换:使用 index(var.availability_zones, each.value) 生成子网索引。
- 代码转换:使用 count 按条件创建可选资源(如 internet gateway)。
- 代码转换:使用 merge 合并公共 tags 与资源专属标签。
- 代码转换:使用 try 安全输出可选资源的属性(如 aws_internet_gateway.main[0].id)。
- 代码转换:将变量集中在 variables.tf,为每个变量提供 description、type,必要时提供 default 和 validation。
- 代码转换:将输出集中在 outputs.tf,为每个输出提供 description 和 value。
- 代码转换:在根配置中用 module 块调用新模块,传入 source 和必要输入变量。
- 状态迁移:编写 moved 块或 state mv 前,先检查当前 state 并映射现有资源地址。
- 状态迁移:优先使用稳定且更省 token 的文档化命令:terraform state list 枚举资源地址。
- 状态迁移:需要解析属性值时使用 terraform show -json | jq '.values.root_module'。
- 状态迁移:注意 terraform show -json 需要先安装 providers(terraform init)。
- 状态迁移:仅当 providers 不可用且无法 init、只需粗略信息(地址、outputs、serial/lineage)、或必须避免执行 Terraform 时,才回退到 raw state(terraform state pull / terraform.tfstate)。
- 状态迁移:避免把 raw version-4 state 格式当作稳定接口解析。
- 状态迁移:state 在不同格式中都会明文包含敏感值,永远不要把 state 内容回显到日志或输出中。
- 状态迁移:Terraform 1.1+ 使用 moved 块生成迁移计划,把旧地址映射到新模块地址。
- 状态迁移:对 Terraform 1.1 之前版本,使用 terraform state mv 手动迁移,例如 terraform state mv aws_vpc.main module.vpc.aws_vpc.main。
- 状态迁移:对 for_each 资源,手动迁移命令要使用正确的实例键,例如 terraform state mv aws_subnet.public_1 'module.vpc.aws_subnet.public["us-east-1a"]'。
- 状态迁移:对 count 资源,手动迁移命令要使用正确的索引,例如 terraform state mv aws_internet_gateway.main 'module.vpc.aws_internet_gateway.main[0]'。
- 模块文档:编写 README,包含 Overview 概述。
- 模块文档:README 包含 Features 功能列表。
- 模块文档:README 包含 Usage 用法和 HCL 示例。
- 模块文档:README 包含 Requirements 表(Terraform 版本、provider 版本要求)。
- 模块文档:README 包含 Inputs 表。
- 模块文档:README 包含 Outputs 表。
- 模块文档:README 引用 Examples 目录中的完整示例。
- 测试:使用 terraform-test 技能。
- 测试:创建 .tftest.hcl 或 .tftest.json 测试文件,包含测试配置和 run 块。
- 测试:使用 test 块定义测试级设置(Terraform 1.6.0+)。
- 测试:使用 run 块定义单个测试场景,可包含变量、provider 配置和断言;每个测试文件至少一个 run 块。
- 测试:使用 assert 块包含必须为真的条件;断言失败导致测试失败。
- 测试:使用 mock provider 模拟 provider 行为而不创建真实基础设施(Terraform 1.7.0+)。
- 测试:选择测试模式:apply 模式(默认,创建真实基础设施)或 plan 模式(仅验证逻辑,不创建资源)。
- 测试:按 tests/ 目录组织测试文件,用 unit_test.tftest.hcl 表示 plan 模式单元测试,用 integration_test.tftest.hcl 表示 apply 模式集成测试。
- 重构模式 1 资源分组:将相关资源抽取为内聚模块,例如 Networking(VPC、Subnets、Route Tables)、Compute(ASG、Launch Templates、Load Balancers)、Data(RDS、ElastiCache、S3)。
- 重构模式 2 配置分层:创建带默认值的 base 模块,再用环境特定 wrapper 模块继承基础并添加生产特定配置。
- 重构模式 3 组合:创建小而聚焦的模块,并通过根模块传递依赖(如 vpc_id、subnet_ids、sg_ids)。
- 避免过度抽象:不要创建过于通用的模块(如 variable "resources" { type = map(map(any)) }),而应使用具体类型化接口(如 database_config object)。
- 避免紧耦合:不要让模块间直接互相引用;应通过根模块传递依赖。
- 避免状态迁移错误:始终先在非生产环境测试迁移。
- 避免状态迁移错误:用 terraform plan -out=migration.tfplan 创建计划以验证迁移后无变更。
- 避免状态迁移错误:用 terraform show migration.tfplan 仔细审查计划。
- 避免状态迁移错误:仅当计划显示无变化时才执行 terraform apply migration.tfplan。
- 版本控制:为模块使用语义化版本。
- 版本控制:模块 source 使用带 ref 的 Git 地址(如 git::https://github.com/org/terraform-modules.git//vpc?ref=v1.2.0)和 version 约束(如 ~> 1.2)。
- 版本控制:生产环境固定到具体版本。
- 版本控制:开发环境可使用版本范围。
- 成功标准:模块具有单一、定义明确的职责。
- 成功标准:所有变量都有描述和类型。
- 成功标准:验证规则能阻止无效配置。
- 成功标准:输出为消费者提供足够信息。
- 成功标准:文档包含用法示例。
- 成功标准:测试验证模块行为。
- 成功标准:状态迁移完成且没有资源被重建。
- 成功标准:重构后 terraform plan 没有差异。
适用边界 · 注意事项
- 不适用于非 Terraform/IaC 配置,或没有现有 Terraform state 需要迁移的场景。
- 不适用于资源之间没有清晰逻辑边界、生命周期高度混杂且无法先在生产外验证状态迁移的场景。
- 不适用于无法运行 terraform init、terraform state list/show 等状态检查命令的环境。