一个团队手动点击云控制台;没有人知道生产环境应该是什么样子。
采用 IaC。配置存储在版本控制文件中——这些文件是权威的真相来源,而不是云控制台。
原因: 审计跟踪、同行评审、回滚和复制都源于版本控制。手动配置不具备这些。
HashiCorp Terraform Associate
最后审核:2026年5月
004 考试涉及的架构模式快速参考。从头到尾阅读,或跳转到任意章节。
一个团队手动点击云控制台;没有人知道生产环境应该是什么样子。
采用 IaC。配置存储在版本控制文件中——这些文件是权威的真相来源,而不是云控制台。
原因: 审计跟踪、同行评审、回滚和复制都源于版本控制。手动配置不具备这些。
选择描述期望的最终状态,还是编写达到该状态的步骤脚本。
Terraform 是声明式的。你描述目标;Terraform 会找出 API 调用。Ansible、Bash 脚本、自定义 SDK 是命令式的。
原因: 声明式配置是幂等的,无论初始状态如何都能收敛。命令式脚本必须考虑每个转换。
工程师希望相同的 `terraform apply` 能够安全地重复运行,而不会重复创建资源。
设计上是幂等的。重复应用相同的配置会收敛到相同的状态——没有重复,没有漂移。
检测实际状态何时与配置不符(有人在控制台中进行了点击)。
`terraform plan -refresh-only` 读取当前的云状态并报告与状态的差异,但不提出更改建议。
区分初始配置和持续操作。
第 0 天 = 设计和规划。第 1 天 = 初始配置(首次应用)。第 2 天 = 持续操作:修补、扩缩、证书轮换、漂移修正。
原因: 大多数生产工作是第 2 天的工作。IaC 工具必须支持迭代,而不仅仅是首次部署。
降低控制台漂移的风险;要求所有基础设施更改都经过审核。
使用 IaC 实现 GitOps:git 是真相的来源,PR 触发计划,合并触发应用。通过 SCP/IAM 阻止直接控制台访问。
工作负载跨越 AWS 和 GCP;团队希望使用一个工具、一个工作流。
Terraform 在一个配置中使用多个 provider:`hashicorp/aws` + `hashicorp/google`。一个 provider 的输出作为另一个的输入。
原因: 与 provider 无关的核心;每个云的 SDK 存在于可插拔的 provider 中。CloudFormation/ARM 是单云的。
标准的 Terraform 生命周期步骤。
`init`(下载 provider + 后端)→ `plan`(预览)→ `apply`(执行)→ `destroy`(销毁)。`plan` 是只读且安全的。
为什么 Terraform 需要状态文件,而不是每次运行时都查询云?
状态将配置地址(`aws_instance.web`)映射到实际的资源 ID,跟踪依赖关系,并缓存元数据。没有它,Terraform 无法知道它管理哪些云资源,哪些是在其他地方创建的。
在开源 CLI 和 HCP Terraform 之间选择。
个人/小型团队/无策略强制执行 → 带远程后端的 OSS CLI。多个团队/Sentinel/OPA 策略/VCS 驱动的运行/动态凭证 → HCP Terraform。
原因: 两者都运行相同的 Terraform 二进制文件;HCP 增加了协作、治理和远程运行器基础设施。
配置虚拟机与在虚拟机内部配置软件。
Terraform 配置云资源(VMs, networks, IAM)。Ansible/Chef/Puppet 在虚拟机内部配置软件。它们是互补的,而不是竞争关系。
纯 AWS 商店在争论 CloudFormation 与 Terraform。
CloudFormation 具有更紧密的 AWS 集成、原生回滚和零状态文件管理。Terraform 在多云、更大的模块生态系统和 HCL 人机工程学方面胜出。如果仅限 AWS 且回滚最重要,则选择 CFN;否则选择 Terraform。
为可复现的安装锁定 provider 来源和版本。
在 `terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } } }` 中声明。
原因: 如果没有明确的 `required_providers`,Terraform 会假定使用旧版注册表命名空间,并可能选择不兼容的版本。
配置中有 AWS 的 `required_providers`,但没有 `provider "aws"` 块。
Terraform 会创建一个默认的空 provider 配置。AWS provider 然后按照其标准优先级读取 `AWS_ACCESS_KEY_ID`/`AWS_PROFILE`/IMDS。
原因: 明确的 `provider` 块是可选的;只有在需要覆盖默认值或别名多个实例时才需要。
决定使用哪个版本约束运算符。
`~> 5.0` 允许 `>= 5.0, < 6.0`(任意 5.x 版本)。`~> 5.0.1` 允许 `>= 5.0.1, < 5.1.0`(仅补丁更新)。`>= 5.0` 无上限。`= 5.2.0` 精确版本。`!= 5.3.0` 排除版本。
原因: 悲观运算符 `~>` 只允许最右侧的版本组件增长。
`terraform init` 实际上做了什么?
根据 `required_providers` 下载 provider,初始化后端,下载模块源,并写入 `.terraform/` 和 `.terraform.lock.hcl`。在 `plan` 或 `apply` 之前是必需的。
在 `init` 之后出现了 `.terraform.lock.hcl` 文件。是提交它还是添加到 gitignore?
提交它。锁定文件记录精确的 provider 版本 + 加密校验和。确保每个协作者和 CI 运行器安装相同的 provider。
原因: 没有它,`terraform init` 可能会在不同的机器上选择一个新的兼容版本,从而引入意想不到的差异。
在 `.tf` 文件中标准化空格、对齐和缩进。
`terraform fmt` 会就地重写 `.tf` 文件以符合规范样式。在预提交钩子和 CI 中运行。
在不访问云 API 的情况下捕获语法错误和类型不匹配。
`terraform validate` 检查 HCL 语法、类型一致性、必需参数和内部引用。仅限本地运行,无需 provider 身份验证。
原因: 不会捕获 provider 端的问题(身份验证、缺少资源)——这些问题只会在 `plan` 阶段浮现。
CI 在多个项目中重复运行 `terraform init`,每个项目都从头开始下载相同的 provider。
设置 `TF_PLUGIN_CACHE_DIR`(或在 CLI 配置中设置 `plugin_cache_dir`)。provider 只下载一次,并以符号链接的形式链接到每个项目的 `.terraform/` 目录中。
provider 来源地址遵循什么格式?
`<hostname>/<namespace>/<type>` — 例如 `registry.terraform.io/hashicorp/aws`。省略主机名时默认为公共 Terraform Registry。Namespace = 供应商。Type = provider 名称。
阻止协作者运行不兼容的 Terraform CLI 版本。
`terraform { required_version = ">= 1.5, < 2.0" }`。如果正在运行的版本不匹配,CLI 将拒绝操作。
为 CI/CD 运行器选择 provider 身份验证。
最佳实践:短生命周期的动态凭证(OIDC 信任到 AWS/Azure/GCP,HCP Terraform 动态 provider 凭证)。可接受:环境变量(`AWS_ACCESS_KEY_ID`)。避免:硬编码的 `provider` 块凭证。
原因: 配置中静态、长期存在的秘密是凭证泄露事件的主要原因。
顶层设置存储在哪里?
`terraform { ... }` 块包含 `required_version`、`required_providers`、`backend`、`cloud` 和实验设置。跨文件的多个 `terraform` 块会被合并。
资源存在于状态中,但不再需要由 Terraform 管理;云资源必须继续运行。
`terraform state rm <addr>`。从状态中移除,而不销毁云资源。
重构了资源的名称或将其移入模块;希望避免销毁/重新创建。
`terraform state mv <old> <new>`。更新状态映射,而不触及云资源。
原因: 在 Terraform 1.1+ 中,更推荐在 HCL 中使用 `moved` 块——它是可审核、版本控制的,并且在 PR 计划中有效。
内部 provider 注册表 URL 已更改;现有状态仍引用旧的源地址。
`terraform state replace-provider <old-source> <new-source>`。重写状态中的 provider 引用。
应用在运行中途崩溃;DynamoDB 锁卡住了,其他工程师被阻止。
`terraform force-unlock <LOCK_ID>`(锁 ID 在错误消息中)。解锁前请确认没有其他人在运行。
原因: 锁在崩溃时不会自动释放,因为清理阶段从未执行。
现有的手动创建的 S3 存储桶需要纳入 Terraform 管理,而无需重新创建。
编写资源块,然后 `terraform import aws_s3_bucket.legacy legacy-bucket-name`。状态现在记录了现有存储桶;后续计划只会显示漂移。
需要通过 CI 可复现地导入许多资源,而不是通过即席 CLI 命令。
使用 `import` 块(Terraform 1.5+):`import { to = aws_s3_bucket.legacy, id = "legacy-bucket-name" }`。导入发生在 `apply` 期间,是版本控制的,并且在计划输出中有效。
调试一个神秘的 provider 错误;需要完整的 HTTP 跟踪。
`TF_LOG=TRACE`(最详细)。`TF_LOG_PATH=./tf.log` 写入文件。其他级别:DEBUG、INFO、WARN、ERROR。
在不应用的情况下,针对当前状态测试 `merge()` 或 `cidrsubnet()` 等表达式。
`terraform console` 打开一个交互式 REPL,其中包含当前配置 + 状态。对于原型化 locals 和 outputs 很有用。
可视化复杂配置的依赖 DAG。
`terraform graph | dot -Tsvg > graph.svg` 生成资源依赖关系的 Graphviz 可视化。
从 CI 脚本读取 Terraform 输出。
`terraform output -json <name>` 以 JSON 格式输出,安全用于 `jq` 解析。普通的 `terraform output` 是人可读的格式,不适合脚本。
强制在下一次 apply 时重新创建单个资源。
`terraform apply -replace=aws_instance.web` (Terraform 1.x)。旧版 `terraform taint` 已弃用。
原因: `-replace` 在计划输出中可审核;`taint` 在下一次计划之前会默默地修改状态。
检查状态中当前跟踪的内容。
`terraform state list` 显示所有资源地址。`terraform state show <addr>` 显示单个资源的属性。对于索引资源,请使用引号:`terraform state show 'aws_instance.web[0]'`。
选择一个模块来源。
本地路径 → `./modules/vpc`。公共注册表 → `terraform-aws-modules/vpc/aws`。Git → `git::https://github.com/org/repo.git//path?ref=v1.0`。也支持 S3/HTTP/Mercurial。
锁定注册表模块以仅允许补丁更新。
`version = "~> 3.5.2"` 允许 `>= 3.5.2, < 3.6.0`。对于次要版本更新容忍度,请使用 `~> 3.0`(任意 3.x)。本地路径模块不支持 `version`。
具有组织范围可见性的内部专用模块。
HCP Terraform 私有模块注册表。地址:`app.terraform.io/<org>/<name>/<provider>`。版本从遵循语义版本控制(`v1.2.0`)的 Git 标签中检测。
公共注册表和 HCP Terraform 私有注册表都通过什么机制检测模块版本?
遵循语义版本控制(`v1.2.0` 或 `1.2.0`)的 Git 标签。推送新标签 → 新版本可用。
将创建的存储桶的 ARN 暴露给调用配置。
在模块内部:`output "bucket_arn" { value = aws_s3_bucket.this.arn }`。调用者将其读取为 `module.<name>.bucket_arn`。
参数化模块,以便调用者可以提供 CIDR、名称、标签。
模块根目录的 `variable` 块定义输入。调用者以内联方式传递它们:`module "vpc" { source = "...", cidr = "10.0.0.0/16" }`。
模块接收数据库密码作为输入;该值绝不应出现在 CLI 输出中。
将变量标记为 `sensitive = true`。应用/计划输出显示 `(sensitive value)`。注意:仍在状态中以纯文本形式存储。
构建一个“平台”模块,该模块内部调用 VPC + EKS + RDS 模块。
一个模块可以调用其他模块。将一个模块的输出作为下一个模块的输入:`eks_subnet_ids = module.vpc.private_subnet_ids`。
使用不同的输入实例化相同的模块 N 次(例如,每个区域一次)。
`module "regional" { for_each = toset(["us-east-1", "eu-west-1"]), source = "...", region = each.key }`。通过 `module.regional["us-east-1"].output_name` 引用。
模块需要一个别名 provider(例如,用于非默认区域)。
调用者在 `module` 调用中传递 `providers = { aws = aws.us_west }` 块。模块在 `required_providers` 中声明 `configuration_aliases = [aws.us_west]`。
寻址公共注册表模块。
`<NAMESPACE>/<NAME>/<PROVIDER>` — 例如 `terraform-aws-modules/vpc/aws`。Git 标签驱动版本。
在开发/预生产/生产环境之间重用相同的模块。
两种模式:(1) 带有一个根配置 + 每个工作区 `*.tfvars` 的工作区。 (2) 每个环境一个根配置(`envs/dev/main.tf`、`envs/prod/main.tf`),每个根配置调用共享模块。模式 2 对于多团队隔离更常见。
确保 CI 精确应用计划中已审核的内容,步骤之间没有漂移。
`terraform plan -out=tfplan` 保存计划。然后 `terraform apply tfplan` 应用该精确计划。拒绝重新计划消除了检查时/使用时风险。
解码计划输出符号:`+`、`-`、`~`、`-/+`、`<=`。
`+` 创建。`-` 销毁。`~` 原地更新。`-/+` 销毁然后创建(替换)。`<=` 读取(数据源)。替换符号表示 `forces replacement` 属性已更改。
快速修复一个损坏的资源,而不触及配置的其余部分。
`terraform apply -target=aws_instance.web`。谨慎使用——它绕过了依赖跟踪,可能导致状态不一致。记录每次使用 `-target` 的原因。
原因: HashiCorp 明确表示 `-target` 用于异常故障排除,而非正常工作流。
强制重新创建特定资源。
`terraform apply -replace=aws_instance.web`。取代了已弃用的 `terraform taint` 工作流。
销毁当前配置中的所有内容。
`terraform destroy`(或 `terraform apply -destroy`)。计划配置的反向操作。除非使用 `-auto-approve`,否则需要确认。
销毁一个资源而不影响其他资源。
`terraform destroy -target=aws_instance.web`。与 apply 的 `-target` 警告相同——谨慎使用。
检测漂移但不提出更改建议。
`terraform plan -refresh-only`。从实际资源刷新状态并报告差异,但不生成修改资源的计划。
原因: 取代了已弃用的独立 `terraform refresh` 命令。
资源 A 必须在资源 B 之前存在,但 B 不引用 A 的属性。
将 `depends_on = [resource_a.name]` 添加到 B。仅当隐式属性引用无法表达依赖关系时使用(例如,IAM 策略必须在 EC2 使用它之前传播)。
在不停机的情况下替换资源。
`lifecycle { create_before_destroy = true }`。Terraform 首先创建新资源,重定向引用,然后销毁旧资源。
原因: 默认是先销毁后创建,这会导致停机。注意:依赖资源也必须支持此更改。
防止意外 `terraform destroy` 生产数据库。
`lifecycle { prevent_destroy = true }`。如果对该资源提议销毁,`terraform plan` 将会失败。
原因: 最后一道防线——不保护 `terraform state rm` 后跟销毁的情况。
应用程序在运行时设置了一个标签,但 Terraform 持续将其恢复。
`lifecycle { ignore_changes = [tags["LastDeployed"]] }`。Terraform 会忽略这些属性上的漂移。
每当相关的启动模板发生更改时(不直接修改 EC2),替换 EC2 实例。
`lifecycle { replace_triggered_by = [aws_launch_template.web.latest_version] }` (Terraform 1.2+)。当任何列出的值发生更改时,实例将被替换。
CI/CD 流水线在成功的计划作业后应用;无人手动操作。
`terraform apply -auto-approve` 跳过交互式确认。结合保存的计划文件(`terraform apply tfplan`)使 CI 具有确定性。
云 provider 对 Terraform 进行速率限制;许多资源创建间歇性失败。
`terraform apply -parallelism=5`(默认 10)限制并发资源操作。
两个资源之间没有相互依赖关系。
Terraform 并行创建它们。DAG 仅沿引用边缘强制执行序列。
原因: 相同 DAG 深度的资源可以并发运行,最多达到 `-parallelism` 设定的数量。
变量在 `terraform.tfvars`、`TF_VAR_region` 环境变量和 `-var=region=...` CLI 标志中都有定义。
优先级最高者胜出:CLI `-var` / `-var-file` > `*.auto.tfvars`(按字母顺序)> `terraform.tfvars` > `TF_VAR_*` 环境变量 > 变量默认值。
传递特定于环境的变量值,而无需将秘密提交到 git。
`terraform apply -var-file=prod.tfvars`。`*.auto.tfvars` 文件会自动加载。`terraform.tfvars` 也会自动加载。
在 HCL 中重构资源的名称/路径,而无需销毁/重新创建。
`moved { from = aws_instance.old_web; to = aws_instance.new_web }` (Terraform 1.1+)。可在 PR 计划中审核;取代了临时的 `terraform state mv`。
原因: 存在于 HCL 中,受版本控制,在协作者之间是幂等的。`state mv` 是一次性的 CLI 副作用。
从配置中移除资源而不销毁它。
`removed { from = aws_instance.legacy; lifecycle { destroy = false } }` (Terraform 1.7+)。取代了临时的 `terraform state rm`。设置 `destroy = true` 也会销毁。
CI 需要知道计划是否有更改,而无需解析文本。
`terraform plan -detailed-exitcode`。0 = 无更改,1 = 错误,2 = 存在更改。驱动“仅计划”PR 作业。
状态实际上包含什么?
资源地址 → 云资源 ID 映射、属性快照、依赖图元数据以及模块/provider 引用。用于规划差异和检测漂移。
单个工程师在本地进行原型设计——本地状态可以吗?
对于一次性个人工作可以。Terraform 会将 `terraform.tfstate` 写入配置旁边。一旦涉及第二个人、CI 运行器或生产环境,立即切换到远程后端。
团队需要工程师之间共享状态,具有锁定 + 版本控制,托管在 AWS 上。
S3 后端。配置 `bucket`、`key`、`region`。添加 `dynamodb_table` 用于状态锁定。启用存储桶版本控制 + SSE-KMS 服务器端加密。
原因: S3 + DynamoDB 是规范的 AWS 托管远程后端。版本控制可以从损坏或意外覆盖的状态中恢复。
Azure 托管的共享状态,CI 中没有静态凭据。
后端类型 `azurerm`。设置 `use_msi = true`(托管标识)或 `use_oidc = true`,以便运行器通过其标识进行身份验证。原生 Blob 租约处理锁定。
GCP 托管的共享状态,具有对象版本控制。
后端类型 `gcs`。配置 `bucket` + `prefix`。GCS 具有内置的对象世代(版本控制);通过 GCS 对象锁进行锁定。
两名工程师同时对同一个 S3 后端状态运行 apply。
DynamoDB 锁定表可防止并发写入。第一个获取锁,第二个会看到 `state lock failed` 错误,并且必须等待或在锁过期时 `force-unlock`。
原因: 没有 DynamoDB,并发应用可能会损坏 S3 状态文件。
HCP Terraform——我需要配置 DynamoDB 吗?
不需要。HCP Terraform 原生处理状态、锁定和加密。你只需声明 `cloud { ... }` 而不是后端。
从本地状态迁移到 S3 后端。
添加 `backend "s3"` 块。运行 `terraform init -migrate-state`。Terraform 会将本地状态复制到 S3 并提示确认。
后端配置已更改(例如新存储桶),但你不想迁移现有状态。
`terraform init -reconfigure`。重新初始化后端并忽略现有的本地缓存。当你打算从头开始时使用。
使用一个根配置管理开发/预生产/生产环境。
工作区——`terraform workspace new staging`,`terraform workspace select prod`。每个工作区都有自己的状态文件。在 HCL 中通过 `terraform.workspace` 引用。
原因: 轻量级选项。对于真正的隔离(不同的 IAM、单独的账户),更推荐使用每个环境的根配置。
本地后端在哪里存储工作区状态?
`default` 工作区 → 项目根目录中的 `terraform.tfstate`。其他工作区 → `terraform.tfstate.d/<NAME>/terraform.tfstate`。
在预生产资源存在时运行 `terraform workspace select prod`。
预生产资源不受影响。切换工作区只会改变 Terraform 下次读取哪个状态文件——这是一个本地指针更改。
查看可用工作区和活动工作区。
`terraform workspace list`(星号标记当前)。`terraform workspace show` 仅打印当前名称。
安全团队询问 Terraform 如何处理状态中的 RDS 密码。
敏感值在状态中以**纯文本**形式存储。缓解措施:加密静态后端(S3 SSE-KMS,HCP 原生),限制对状态存储桶的 IAM 访问,并尽可能避免将秘密放入 Terraform。
原因: `sensitive = true` 标志只在 CLI 输出中隐藏值,而不隐藏状态。
合规性要求对状态进行静态加密。
S3:在存储桶上启用 SSE-KMS。Azure:存储账户加密(默认开启)。GCS:客户管理的加密密钥。HCP Terraform:原生静态加密。
工程师不小心对生产环境运行了 `terraform destroy`。状态现在为空。
从 S3 版本控制中恢复状态文件的先前版本,然后运行 `terraform plan` 以查看 Terraform 现在认为需要创建/导入什么。结合云端恢复(快照,`aws backup`)已销毁的资源。
状态文件看起来不对;想直接编辑它。
不要。使用 `terraform state` 子命令(`mv`、`rm`、`replace-provider`、`pull`、`push`)。手动编辑 JSON 会跳过完整性检查并破坏血缘关系。
检查原始远程状态 JSON,或推送恢复的状态文件。
`terraform state pull` 将当前远程状态写入标准输出。`terraform state push <file>` 用给定文件覆盖远程状态。Push 是破坏性的——请先备份。
通过 Terraform 传递临时 API 令牌,而不会将其存储在状态中。
将变量标记为 `ephemeral = true` (Terraform 1.10+)。瞬态值绝不会持久化到状态或计划文件中。要通过模块输出导出,也要将输出标记为 `ephemeral = true`。
原因: `sensitive` 在 CLI 中隐藏,但以纯文本形式存储在状态中。`ephemeral` 确实从未存储。
`sensitive` 参数和仅写入参数(例如 `password_wo`)之间的区别。
`sensitive` 以纯文本形式存储在状态中,仅在 CLI 中进行编辑。仅写入属性**绝不会**存储在状态中。为了检测仅写入属性的更改,Terraform 使用一个伴随版本字段(例如 `password_wo_version`)。
在状态中显示 `count` 资源的一个元素。
引用地址:`terraform state show 'aws_instance.web[0]'`。不带引号,shell 可能会解释括号。
不同的团队需要独立操作,互不干扰对方的状态。
每个团队(或每个团队的每个环境)一个状态文件。单独的后端/存储桶。使用 `terraform_remote_state` 数据源以只读方式读取另一个状态。
网络团队管理 VPC;应用团队需要 VPC ID。
`data "terraform_remote_state" "network" { backend = "s3"; config = { bucket = "...", key = "network/terraform.tfstate" } }`。将输出引用为 `data.terraform_remote_state.network.outputs.vpc_id`。
原因: 只读——网络团队的状态不会被锁定或修改。
针对 Terraform 0.13 编写的配置;想要使用 1.x 版本。
状态文件是向前兼容的:1.x 可以读取 0.13 的状态。HashiCorp 建议进行增量升级(0.13 → 0.14 → … → 1.x),针对每个版本运行状态。
有人通过控制台修改了一个安全组;希望 Terraform 重新断言或接受新状态。
重新断言:`terraform apply` —— Terraform 恢复到配置。接受:更新 HCL 以匹配实际情况,然后应用(无差异)。首先通过 `terraform plan -refresh-only` 检测。
强类型化变量。
基本类型:`string`、`number`、`bool`。集合:`list(<type>)`、`set(<type>)`、`map(<type>)`。结构化:`object({...})`、`tuple([...])`。仅在真正多态时使用 `any`。
将 `environment` 限制为 dev/staging/prod。
`variable "environment" { validation { condition = contains(["dev","staging","prod"], var.environment); error_message = "..." } }`。允许多个 `validation` 块;所有块都必须通过。
输出数据库密码,而不让其出现在 `terraform output` 中。
`output "db_password" { value = ...; sensitive = true }`。CLI 显示 `(sensitive value)`。仍然可以通过 `terraform output db_password` 或 `-json` 读取(有意为之——用于脚本)。
计算一个值一次,并在多个资源中重用。
`locals { common_tags = merge(var.tags, { Project = var.project }) }`。引用为 `local.common_tags`。不能从模块外部覆盖。
查找现有 AMI,而不对其进行管理。
`data "aws_ami" "ubuntu" { most_recent = true; filter { ... } }`。只读。将属性引用为 `data.aws_ami.ubuntu.id`。
创建 N 个相似资源——选择 `count` 或 `for_each`。
当项目具有稳定标识(区域名称、环境键)时,使用 `for_each`(带 map 或 set)。当“我需要 N 个副本,顺序不重要,标识只是一个索引”时,使用 `count`。在 `count` 中间添加/删除会导致销毁/重新创建;`for_each` 保留标识。
为字符串列表中的每个项目创建一个资源。
`for_each = toset(["a", "b", "c"])`。`each.key` 和 `each.value` 都给出字符串。对于 map:`for_each = var.users` — `each.key` = map 键,`each.value` = map 值。
生成可变数量的嵌套块(例如,入站规则)。
`dynamic "ingress" { for_each = var.rules; content { from_port = ingress.value.from; ... } }`。如果需要,`iterator` 参数可以重命名迭代器。
获取 `count` 资源所有实例的属性列表。
`aws_instance.web[*].id` 返回 ID 列表。适用于 `count` 和 `for_each`(但 `for_each` 生成无序 map,因此 `values(aws_instance.web)[*].id`)。
根据条件设置值。
三元运算符:`var.is_prod ? 5 : 1`。两个分支必须产生相同类型。
合并两个 map;在键冲突时,第二个 map 的值胜出。
`merge(local.defaults, local.overrides)`。最右侧的 map 胜出。适用于标签组合。
如果键缺失,则读取带有默认值的 map 值。
`lookup(var.config, "region", "us-east-1")`。当键不存在时返回默认值。对于深度可选结构,优先使用可选的 `try()`。
将嵌套列表折叠成一个扁平列表。
`flatten([["a","b"], ["c"], [["d","e"]]])` → `["a","b","c","d","e"]`。递归地扁平化列表;保留顺序。
将 Terraform map 嵌入到 IAM 策略文档中。
`jsonencode({Version = "2012-10-17", Statement = [...]})`。生成 JSON 字符串。逆操作:`jsondecode()`。
使用变量值渲染模板化的用户数据脚本。
`templatefile("init.sh.tpl", { region = var.region, env = var.env })`。模板使用 `${region}` 语法。静态渲染的新替代方案:`file()` + `format()`。
从 VPC 范围中划分出子网 CIDR。
`cidrsubnet("10.0.0.0/16", 8, 0)` → `10.0.0.0/24`。第一个参数 = 父级,第二个 = 扩展位数,第三个 = 子网编号。
读取可能不存在的值;回退到默认值。
`try(yamldecode(file("config.yaml")), { defaults = true })`。从左到右评估;返回第一个没有错误的表达式。
迭代匹配 glob 模式的文件。
`fileset(path.module, "configs/*.json")` 返回一组路径。结合 `for_each` 管理每个文件的资源。
同一 provider 在两个区域(例如 AWS us-east-1 + us-west-2)。
两个 `provider "aws" { alias = "..." }` 块。资源通过 `provider = aws.us_west` 选择加入。模块通过 `configuration_aliases` 接受别名。
在新创建的虚拟机上运行 shell 命令。
资源内的 `remote-exec` provisioner。最后的手段——优先使用 cloud-init、用户数据或配置管理。Provisioner 不在状态中跟踪,并且不会在漂移时重新运行。
运行一个不对应于云资源的命令(例如 CLI 调用)。
`resource "null_resource" "trigger" { triggers = { sha = sha1(file(".")) }; provisioner "local-exec" { command = "..." } }`。当 `triggers` 更改时重新运行。
持续验证运行时不变性(例如,健康端点返回 200),而不阻塞 apply。
`check "endpoint" { data "http" "h" { url = "..." }; assert { condition = data.http.h.status_code == 200; error_message = "..." } }`。在 plan/apply 时运行;失败是警告,而不是硬错误。
原因: `check` 允许仅在检查内部使用的 scoped data source。`precondition`/`postcondition` 是在 plan/apply 时的硬错误。
如果 AMI 太旧,则计划失败。
`lifecycle { precondition { condition = data.aws_ami.x.creation_date > "2024-01-01"; error_message = "..." } }`。硬失败,在适当的时候进行前/后评估。
具有固定形状位置值的变量。
`type = tuple([string, number, bool])` 要求按该顺序精确包含三个元素。与列表(同质、可变长度)不同。
强类型化结构化输入(例如 `database = { instance_class = string, allocated_storage = number }`)。
`type = object({ instance_class = string, allocated_storage = number, multi_az = optional(bool, false) })`。`optional(<type>, <default>)` 使属性成为可选。
`*.tfvars` 文件是如何加载的?
`terraform.tfvars` 和 `*.auto.tfvars` 会自动加载(`auto` 文件按字母顺序)。其他名称需要 `-var-file=path.tfvars`。
为 Terraform 模块编写自动化测试。
`.tftest.hcl` 文件包含 `run "name" { command = plan|apply, assert { condition = ..., error_message = ... } }`。`command = plan` 没有副作用;`command = apply` 实际创建资源。
将变量传递到测试运行中。
文件级别的 `variables { ... }` 块适用于所有运行。每个运行的 `variables { ... }` 仅覆盖该运行。
在 HCP Terraform 中选择工作区执行模式。
VCS 驱动(git push 自动计划,最常见)。CLI 驱动(开发人员在本地运行 `terraform plan/apply`,HCP 保存状态)。API 驱动(Terraform 运行由 API 触发,由自动化/CD 系统使用)。
HCP Terraform 运行中的阶段顺序。
计划 → 成本估算(如果启用)→ 策略检查 (Sentinel/OPA) → 手动或自动应用。强制性策略失败或运行任务失败会中止管道。
强制所有 S3 存储桶都已加密,如果违反则阻止应用。
具有硬强制执行的 Sentinel 策略。检查计划;失败会阻止应用。软强制允许管理员覆盖。建议性策略只会记录日志但永不阻止。
将第三方安全扫描器集成到 HCP Terraform 运行管道中。
在计划后阶段运行任务。HCP 将计划 POST 到您的端点;端点回复通过/失败。强制执行在失败时阻止应用;建议性仅警告。
在合并之前显示拉取请求的影响。
推测性计划在 PR(或分支)上运行,将结果评论回 PR,并且永不应用。当启用 VCS 集成时自动触发。
避免在 HCP Terraform 变量中将 AWS 访问密钥存储为静态秘密。
动态 provider 凭证。HCP Terraform 通过 OIDC 信任向 AWS/Azure/GCP 请求短期凭证。无静态密钥;每个运行的身份;审计友好。
原因: 静态密钥容易泄露。OIDC 信任将凭证绑定到工作区 + 运行,并在一个小时内过期。
在多个工作区之间共享相同的 provider 凭证。
变量集。在组织/项目级别定义一次,并附加到多个工作区。更新无需逐个工作区编辑即可传播。
HCP Terraform 中的“默认项目”是什么?
一个内置项目,存在于每个组织中,不能删除(允许重命名)。除非明确分配给另一个项目,否则所有工作区都属于它。
每当上游工作区成功应用后,就应用下游工作区。
运行触发器。在依赖工作区上配置源工作区;HCP 在每次成功的上游应用后,将一个运行排队到依赖工作区上。