terraform
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTerraform & OpenTofu
Terraform & OpenTofu
File Organization & Naming
文件组织与命名规范
| File | Purpose |
|---|---|
| Terraform + provider version requirements |
| Provider configurations |
| Primary resources and data sources |
| Input variables (alphabetical) |
| Output values (alphabetical) |
| Local values |
- Lowercase with underscores: , not
web_apiorwebAPIweb-api - Descriptive nouns excluding resource type: not
aws_instance.web_apiaws_instance.web_api_instance - Singular, not plural
- for singleton resources (one of that type per module)
this - Contextual variable prefixes: not
vpc_cidr_blockcidr
| 文件 | 用途 |
|---|---|
| Terraform及provider版本要求 |
| Provider配置 |
| 核心资源与数据源 |
| 输入变量(按字母排序) |
| 输出值(按字母排序) |
| 本地变量 |
- 使用小写加下划线:,而非
web_api或webAPIweb-api - 描述性名词,不含资源类型:而非
aws_instance.web_apiaws_instance.web_api_instance - 使用单数形式,而非复数
- 单例资源(每个模块中仅一个该类型资源)使用命名
this - 变量添加上下文前缀:而非
vpc_cidr_blockcidr
Block Ordering
代码块排序规则
Resources: / (blank line after) → arguments → nested blocks → → → (last)
countfor_eachtagsdepends_onlifecycleVariables: → → → →
descriptiontypedefaultvalidationnullableEvery variable needs + . Every output needs . Mark secrets .
typedescriptiondescriptionsensitive = true资源块: /(后接空行)→ 参数 → 嵌套块 → → → (放在最后)
countfor_eachtagsdepends_onlifecycle变量块: → → → →
descriptiontypedefaultvalidationnullable每个变量必须包含和。每个输出必须包含。敏感数据需标记。
typedescriptiondescriptionsensitive = trueModule Structure
模块结构
| Type | Scope | Example |
|---|---|---|
| Resource Module | Single logical group | VPC + subnets, SG + rules |
| Infrastructure Module | Collection of resource modules | Networking + compute for one region |
| Composition | Complete infrastructure | Spans regions/accounts |
module-name/
├── main.tf, variables.tf, outputs.tf, versions.tf
├── examples/
│ ├── minimal/
│ └── complete/
└── tests/
└── defaults.tftest.hclKeep modules small (single responsibility). double as documentation and integration test fixtures. Semantic versioning for all published modules.
examples/| 类型 | 范围 | 示例 |
|---|---|---|
| 资源模块 | 单一逻辑组 | VPC+子网、安全组+规则 |
| 基础设施模块 | 资源模块集合 | 单区域内的网络+计算资源 |
| 组合模块 | 完整基础设施 | 跨区域/跨账号部署 |
module-name/
├── main.tf, variables.tf, outputs.tf, versions.tf
├── examples/
│ ├── minimal/
│ └── complete/
└── tests/
└── defaults.tftest.hcl保持模块轻量化(单一职责)。目录同时作为文档和集成测试夹具。所有发布的模块遵循语义化版本规范。
examples/count vs for_each
count vs for_each
| Scenario | Use |
|---|---|
| Boolean toggle (create or skip) | |
| Named/keyed items that may reorder | |
| Fixed identical replicas | |
Default to -- removing a middle item from a list recreates all subsequent resources. Use only for boolean conditionals or truly identical replicas.
for_eachcountcount| 场景 | 适用方式 |
|---|---|
| 布尔开关(创建或跳过) | |
| 带名称/键且可能重排的条目 | |
| 固定数量的相同副本 | |
优先使用——从列表中移除中间项会导致后续所有资源重新创建。仅在布尔条件或完全相同的副本场景下使用。
for_eachcountcountTesting
测试方案
| Situation | Approach |
|---|---|
| Quick validation | |
| Pre-commit | + |
| Logic validation (1.6+) | Native |
| Cost-free unit tests (1.7+) | Native tests + |
| Real infra validation | Native tests with |
Native test essentials ( in ):
.tftest.hcltests/- for fast unit tests;
command = planfor integration (default)command = apply - -- multiple per run block
assert { condition = expr; error_message = "..." } - for negative testing (validate rejection of bad input)
expect_failures = [var.name] - -- plan-mode only, no credentials, fast CI
mock_provider "aws" { mock_resource "..." { defaults = { ... } } } - at file level (all runs) or within a
variables {}block (override)run - Reference prior run outputs:
run.setup.vpc_id - on independent runs with separate state -- creates sync point at next sequential run
parallel = true - required for
state_key = "name"runs with independent stateparallel = true - File naming: (plan mode) vs
*_unit_test.tftest.hcl(apply mode)*_integration_test.tftest.hcl - A block inside a
module {}accepts local paths and registry modules only -- not git or HTTP sources. Repos consuming git-sourced modules must vendor or localize them before they can be tested.run - After a test file completes, resources are destroyed in reverse run-block order. Order dependent runs accordingly (create the bucket before the run that puts objects in it), or the destroy fails and leaves billable resources behind. There is no CLI flag to skip cleanup -- inspect a failure with .
-verbose
Running them:
bash
terraform test # all *.tftest.hcl under tests/
terraform test -filter=vpc_unit_test.tftest.hcl # one test FILE (not a run-block name)
terraform test -verbose # show the plan/apply per run block
terraform test -test-directory=path # non-default test dirSplit by cost in CI: plan-mode unit tests on every PR, apply-mode integration tests on merge only.
| 场景 | 实施方法 |
|---|---|
| 快速验证 | |
| 预提交检查 | 新增 |
| 逻辑验证(1.6+版本) | 原生 |
| 无成本单元测试(1.7+版本) | 原生测试 + |
| 真实基础设施验证 | 原生测试搭配 |
原生测试核心要点(目录下的文件):
tests/.tftest.hcl- 用于快速单元测试;
command = plan用于集成测试(默认值)command = apply - ——每个运行块可包含多个断言
assert { condition = expr; error_message = "..." } - 用于负面测试(验证对非法输入的拒绝)
expect_failures = [var.name] - ——仅支持plan模式,无需凭证,CI执行速度快
mock_provider "aws" { mock_resource "..." { defaults = { ... } } } - 可放在文件级别(所有运行块生效)或
variables {}块内(覆盖全局配置)run - 引用之前运行块的输出:
run.setup.vpc_id - 独立运行块且状态分离时,设置——会在后续顺序运行块处创建同步点
parallel = true - 使用且状态分离的运行块必须设置
parallel = truestate_key = "name" - 文件命名规范:(plan模式) vs
*_unit_test.tftest.hcl(apply模式)*_integration_test.tftest.hcl - 块内的
run仅接受本地路径和注册表模块——不支持git或HTTP源。使用git源模块的仓库必须先将其本地化或 vendoring 后才能测试。module {} - 测试文件执行完成后,资源会按运行块逆序销毁。需按依赖顺序编排运行块(先创建存储桶,再执行向桶中存入对象的运行块),否则销毁会失败并留下产生费用的资源。目前没有CLI flag可跳过清理——可使用查看失败详情。
-verbose
运行测试命令:
bash
terraform test # 运行tests/下所有*.tftest.hcl文件
terraform test -filter=vpc_unit_test.tftest.hcl # 运行单个测试文件(而非运行块名称)
terraform test -verbose # 显示每个运行块的plan/apply详情
terraform test -test-directory=path # 指定非默认测试目录在CI中按成本拆分:每个PR执行plan模式单元测试,仅在合并时执行apply模式集成测试。
Version Pinning
版本固定策略
| Component | Strategy | Example |
|---|---|---|
| Terraform | Pin minor | |
| Providers | Pin major | |
| Modules (prod) | Pin exact | |
| Modules (dev) | Allow patch | |
Key modern features: blocks (1.1+), with defaults (1.3+), native testing (1.6+), mock providers (1.7+), cross-variable validation (1.9+), write-only arguments (1.11+).
Stacks (HCP -- check current release status): orchestrates multiple configs as a single deployment unit -- evaluate for multi-environment patterns.
movedoptional()| 组件 | 策略 | 示例 |
|---|---|---|
| Terraform | 固定小版本 | |
| Providers | 固定大版本 | |
| 生产环境模块 | 固定精确版本 | |
| 开发环境模块 | 允许补丁版本更新 | |
关键现代特性:块(1.1+)、带默认值的(1.3+)、原生测试(1.6+)、mock providers(1.7+)、跨变量验证(1.9+)、只写参数(1.11+)。
Stacks(HCP——请查看当前发布状态):将多个配置作为单个部署单元编排——可评估用于多环境模式。
movedoptional()State & Security
状态与安全
- Remote backend with locking: S3 with (1.10+), Azure Blob, GCS, or Terraform Cloud. Never local state for shared infrastructure. DynamoDB-based S3 locking (
use_lockfile = true) is deprecated and slated for removal -- preferdynamodb_table; both may be set at once while migrating an existing table off.use_lockfile - Encrypt state at rest. Never commit ,
.tfstate, or.terraform/. Always commit*.tfplan..terraform.lock.hcl - on provider for consistent resource tagging.
default_tags - Encryption at rest on all storage. Private networking by default -- public access is opt-in.
- Least-privilege security groups. No ingress without explicit justification.
0.0.0.0/0 - Never hardcode credentials -- use assume_role, OIDC, or secrets managers.
- Pre-commit: auto-format first (-- rewrites files), then verify (
terraform fmt -recursive)terraform validate && tflint && trivy config . - for refactoring resource names/modules without destroy-recreate. Remove block after apply.
moved { from = old; to = new }
- 带锁机制的远程后端:S3搭配(1.10+)、Azure Blob、GCS或Terraform Cloud。共享基础设施绝不能使用本地状态。基于DynamoDB的S3锁(
use_lockfile = true)已被弃用并将被移除——优先使用dynamodb_table;迁移现有表期间可同时设置两者。use_lockfile - 静态加密状态文件。绝不要提交、
.tfstate或.terraform/文件。必须提交*.tfplan文件。.terraform.lock.hcl - 在provider上设置以实现一致的资源标记。
default_tags - 所有存储开启静态加密。默认使用私有网络——公网访问为可选配置。
- 遵循最小权限原则配置安全组。无明确理由时禁止使用的入站规则。
0.0.0.0/0 - 绝不硬编码凭证——使用assume_role、OIDC或 secrets managers。
- 预提交检查:先自动格式化(——自动改写文件),再进行验证(
terraform fmt -recursive)terraform validate && tflint && trivy config . - 重构资源名称/模块时使用,避免销毁重建。apply完成后移除该块。
moved { from = old; to = new }
Troubleshooting
故障排查
- State lock stuck: -- only after confirming no other operation running
terraform force-unlock <ID> - Resource drift: to detect,
terraform plan -refresh-onlyto acceptterraform apply -refresh-only - Replace tainted: (not deprecated
terraform apply -replace=ADDR)terraform taint - Import existing: blocks (1.5+) for declarative import, or
importterraform import ADDR ID
- 状态锁卡住:——仅在确认无其他操作运行时使用
terraform force-unlock <ID> - 资源漂移:检测漂移,
terraform plan -refresh-only接受漂移terraform apply -refresh-only - 替换污染资源:(替代已弃用的
terraform apply -replace=ADDR)terraform taint - 导入现有资源:使用块(1.5+)声明式导入,或
import命令terraform import ADDR ID
Dependency Management
依赖管理
Use with to control deletion ordering without explicit :
localstry()depends_onhcl
locals {
vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this.id, "")
}This forces Terraform to destroy subnets before CIDR associations -- prevents deletion errors.
- for calculated subnet CIDRs -- never hardcode subnets
cidrsubnet(var.vpc_cidr, 8, count.index) - Multi-region: +
provider "aws" { alias = "eu_west_1" }in module blocksproviders = { aws = aws.eu_west_1 }
使用搭配控制删除顺序,无需显式:
localstry()depends_onhcl
locals {
vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this.id, "")
}这会强制Terraform先销毁子网,再销毁CIDR关联——避免删除错误。
- 使用计算子网CIDR——绝不硬编码子网
cidrsubnet(var.vpc_cidr, 8, count.index) - 多区域部署:+ 在模块块中设置
provider "aws" { alias = "eu_west_1" }providers = { aws = aws.eu_west_1 }
Verify
最终验证
Run before declaring done:
bash
terraform fmt -check && terraform validate && tflint && trivy config .All commands must pass with zero errors. Where plan-mode tests exist, add -- restrict this to plan-mode suites, since apply-mode tests stand up real infrastructure and do not belong in a pre-completion check.
terraform test -filter=<unit-test-file>完成前运行以下命令:
bash
terraform fmt -check && terraform validate && tflint && trivy config .所有命令必须零错误通过。若存在plan模式测试,需添加——仅限plan模式套件,因为apply模式测试会创建真实基础设施,不属于完成前检查环节。
terraform test -filter=<unit-test-file>