SuperAPI AI 工具集

terraform

部署与运维

查看项目

更新于 10-15 12:12

技能介绍

用途

本技能面向 Terraform 与 OpenTofu 的配置编写、模块设计、测试、状态管理与 HCL 审查工作。当任务涉及 Terraform、OpenTofu、HCL、tfvars、tftest、state 等内容时使用。

工作规则

重构期间需保留状态与资源地址,并检查 plan 是否出现非预期的替换。

应将经过验证的本地或模拟效果的测试,与访问真实服务或创建计费基础设施的测试分开。Plan 模式仍可读取真实数据源;模拟 apply 可在不创建基础设施的情况下运行。

文件组织与命名

文件用途划分:terraform.tf 存放 Terraform 与 provider 版本要求;providers.tf 存放 provider 配置;main.tf 存放主要资源与数据源;variables.tf 存放输入变量(按字母顺序);outputs.tf 存放输出值(按字母顺序);locals.tf 存放本地值。

命名使用小写加下划线,如 web_api,而非 webAPI 或 web-api。使用描述性名词并排除资源类型,如 aws_instance.web_api 而非 aws_instance.web_api_instance。使用单数而非复数。单例资源(每个模块中该类型只有一个)使用 this。变量使用上下文前缀,如 vpc_cidr_block 而非 cidr。

块排序

资源块顺序:count/for_each(后接空行)→ 参数 → 嵌套块 → tags → depends_on → lifecycle(最后)。

变量块顺序:description → type → default → validation → nullable。

每个变量都需要 type 与 description。每个输出都需要 description。机密信息标记 sensitive = true。

模块结构

模块类型与范围:资源模块(单一逻辑组,如 VPC + 子网、SG + 规则);基础设施模块(资源模块的集合,如某区域的网络 + 计算);组合(完整基础设施,跨区域/账户)。

模块目录结构:module-name/ 下含 main.tf、variables.tf、outputs.tf、versions.tf,以及 examples/(含 minimal/ 与 complete/)和 tests/(含 defaults.tftest.hcl)。

保持模块小巧(单一职责)。examples/ 兼作文档与集成测试夹具。所有已发布模块使用语义化版本。

count 与 for_each

布尔开关(创建或跳过)使用 count = condition ? 1 : 0。可能重排序的命名/键控项使用 for_each = toset(list) 或 map。固定数量的相同副本使用 count = N。

默认使用 for_each:从 count 列表中移除中间项会重建其后所有资源。仅在布尔条件或真正相同的副本时使用 count。

版本固定

Terraform 固定次版本,如 required_version = "~> 1.9.0"。Provider 固定主版本,如 version = "~> 5.0"。模块(生产)固定精确版本,如 version = "5.1.2";模块(开发)允许补丁版本,如 version = "~> 5.1.0"。

关键现代特性:moved 块(1.1+)、带默认值的 optional()(1.3+)、原生测试(1.6+)、mock provider(1.7+)、跨变量验证(1.9+)、只写参数(1.11+)。Stacks(HCP;请查看当前发布状态)将多个配置编排为单一部署单元,可用于评估多环境模式。

状态与安全

使用带锁定的远程后端:S3 配合 use_lockfile = true(1.10+)、Azure Blob、GCS 或 Terraform Cloud。共享基础设施绝不使用本地状态。基于 DynamoDB 的 S3 锁定(dynamodb_table)已弃用并计划移除;优先使用 use_lockfile。迁移现有表时可同时设置两者。

仅 OpenTofu:terraform { encryption { key_provider "pbkdf2" "k" {...} method "aes_gcm" "m" { keys = key_provider.pbkdf2.k } state { method = method.aes_gcm.m } plan { method = method.aes_gcm.m } } } 可在客户端加密状态与 plan 文件(或通过 TF_ENCRYPTION)。使用 fallback { method = method.unencrypted.x } 推出,以便现有明文状态仍可加载;没有 fallback 块时绝不要重命名 key provider 或 method。OpenTofu 还接受 backend {} 参数以及模块 source/version 中的 var./local.(在 init 时解析;不支持状态或 provider 函数引用);同样的 HCL 在 Terraform 中是硬错误("A backend block cannot refer to named values")。

静态加密状态。绝不提交 .tfstate、.terraform/ 或 *.tfplan。始终提交 .terraform.lock.hcl。

在 provider 上设置 default_tags 以保持一致的资源标记。

所有存储启用静态加密。默认使用私有网络;公共访问需显式选择加入。

最小权限安全组。没有明确理由不得使用 0.0.0.0/0 入站。

绝不硬编码凭据;使用 assume_role、OIDC 或密钥管理器。

Pre-commit:先自动格式化(terraform fmt -recursive 会重写文件),再验证(terraform validate && tflint && trivy config .)。

使用带 from 与 to 地址的 moved 块,在不销毁重建的情况下重构资源名称/模块。为下游升级保留历史 moved;仅在所有受影响状态迁移完成后移除,或作为显式破坏性模块发布。

lifecycle { ignore_changes = [attr] } 仅抑制更新,并在配置变更后的首次 plan 时用先前状态值替代,没有"首次 apply"例外。两个常被反向理解的后果:(1)在已配置资源上,配置中的字面值永远不会被写入,ForceNew 也不会触发,因为 ignore_changes 在评估替换前已消除差异,因此用占位符替换已提交值会清除仓库并让远程值保持生效;(2)ignore_changes 在创建时不适用,因此任何后续 -replace、taint、state rm + 重新添加或手动删除都会在带外设置的值上重新植入占位符。配置中只保留容器资源并完全带外提供值,或在 runbook 中为每条替换路径说明恢复步骤。

故障排查

状态锁卡住:terraform force-unlock <ID>,仅在确认没有其他操作运行时使用。

资源漂移:terraform plan -refresh-only 检测,terraform apply -refresh-only 接受。

替换被污染资源:terraform apply -replace=ADDR(而非已弃用的 terraform taint)。

导入现有资源:import 块(1.5+)用于声明式导入,或 terraform import ADDR ID。

依赖管理

使用带 try() 的 locals 控制删除顺序,而无需显式 depends_on:

locals { vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this.id, "") }

这会强制 Terraform 在 CIDR 关联之前销毁子网,从而防止删除错误。

使用 cidrsubnet(var.vpc_cidr, 8, count.index) 计算子网 CIDR;绝不硬编码子网。

多区域:provider "aws" { alias = "eu_west_1" } + 模块块中的 providers = { aws = aws.eu_west_1 }。

验证

声明完成前运行:

terraform fmt -check && terraform validate && tflint && trivy config .

所有命令必须以零错误通过。在选择测试文件前检查 providers、数据源、provisioner 与外部命令。在完成检查中包含安全的 plan 测试与完全模拟的 apply 测试。将真实服务或基础设施测试置于任务的授权与成本边界之后。传入根相对测试文件名,如 terraform test -filter=tests/vpc_unit_test.tftest.hcl,并验证目标文件至少完成一次运行;仅凭退出码可能接受未选择任何测试的未知过滤器。使用 native-test-patterns.md 中经过检查的选择配方。

任务特定参考

在实现或审查匹配行为前阅读相关参考:

原生 plan/apply 测试、夹具排序或 CI 测试选择:native-test-patterns.md。