Terraform 循环与动态资源:count、for_each 与 dynamic

发布时间:2026/10/15 2:39:07
Terraform 循环与动态资源:count、for_each 与 dynamic 只从列表里删掉一个元素terraform plan 却给出 2 to change, 1 to destroy。这篇文章从一次真实的索引漂移index drift事故出发讲清 count、for_each、dynamic 三个循环元参数meta-argument的追踪机制、能力边界与选型方法。一、场景一份配置里的三种重复写配置时遇到的重复分三种数量、身份、结构各管一层工具却有三个选错的代价从一次 plan 说起。重复的对象典型场景对应手段多个同质顶级资源批量创建同配置计算节点count有独立身份的集合按服务名逐个创建任务for_each一个资源内重复的结构块安全组的多条规则dynamic三种重复形似神不似前者关心数量中者关心身份后者关心结构。我早期把三类混为一谈全用 count 硬扛直到线上那次删除事故才分开对待。三类重复如果配错了工具plan 会付出什么代价二、踩坑删一个元素2 更改 1 销毁那次事故的配置用 count 遍历列表五个字符串各生成一个 terraform_data 实例variable my_list { type list(string) default [zero, one, to_delete, two, three] } resource terraform_data my_count { count length(var.my_list) input tf_data-${var.my_list[count.index]} }我从列表里删掉 to_delete只改了一个字符串terraform plan 的输出却是# terraform_data.my_count[2] will be updated in-place ~ input tf_data-to_delete - tf_data-two # terraform_data.my_count[3] will be updated in-place ~ input tf_data-two - tf_data-three # terraform_data.my_count[4] will be destroyed - input tf_data-three - null Plan: 0 to add, 2 to change, 1 to destroy.两个原地更新加一个销毁全部源于一次删除。我当时的判断是 Terraform 算错了复现三遍之后才确认不是偶发。回去翻变更记录才发现预发环境里类似动作已经发生过一次只是当时列表短漂移被巧合掩盖了。注意漂移的根源不是 count 的语法而是它用数字索引给资源编地址。索引一变地址就变地址一变plan 眼里的就是另一个资源——地址机制具体是怎样裁决计划动作的三、原理地址决定追踪键比索引稳Terraform 用资源地址resource address在状态文件里定位每个实例。地址由资源类型、资源名加一段标识组成count 生成数字索引标识for_each 生成键标识。元参数地址形态单实例引用整组引用countaws_instance.server[0]aws_instance.server[0].idaws_instance.serverfor_eachaws_iam_user.the-accounts[“Todd”]aws_iam_user.the-accounts[“Todd”].idaws_iam_user.the-accountsplan 的裁决分两步先比对配置算出的地址集合与状态里的地址集合地址消失判销毁、地址新增判创建集合一致才逐项比对属性属性变化判原地更新无变化才判 no change。数字索引的数值由元素在列表中的位置决定与元素是谁无关键的取值来自元素本身。删掉中间一个元素索引整体前移而键原地不动这正是漂移与否的分水岭也是 count 适合固定池、for_each 适合变动集的根因。反过来说列表只追加不改写的场景里索引与键的差别会被掩盖直到第一次中间删除才暴露。删除列表中间元素前后的地址集合 count索引地址随位置漂移 ┌─ 删除前 ─ [0]zero [1]one [2]to_delete [3]two [4]three ├─ 删除后 ─ [0]zero [1]one [2]two [3]three └─ 裁决 ─── [2] 属性变 - update [3] 属性变 - update [4] 地址消失 - destroy for_each键地址跟内容绑定 ┌─ 删除前 ─ zero one to_delete two three ├─ 删除后 ─ zero one two three └─ 裁决 ─── 仅 to_delete - destroy 其余地址与属性均不变 - no change以键定位还有两个硬约束键必须是已知值uuid、bcrypt、timestamp 这类非纯函数pure function的结果不能作键敏感值也不能作键否则地址会随计划输出暴露。注意非纯函数结果与敏感值都不能作键。机制清楚之后三个元参数各自该在什么场景出场四、方案三个元参数各管一层重复选型时你先看重复发生在哪一层顶层资源用 count 或 for_each资源内部的嵌套块nested block用动态块dynamic block。同一层内再看身份实例可互换、从不单独增删索引足够实例有名字、集合会变键才安全。维度countfor_eachdynamic适用对象资源 / 模块多实例资源 / 模块多实例资源内的嵌套块标识方式数字索引键map key 或 set 成员无独立标识中间增删索引漂移连锁变更键不变则零影响不涉及生命周期条件创建? 1 : 0全有或全无按条件过滤? [1] : []跳过典型场景固定数量同质节点按身份逐个创建安全组规则、监听器条件创建的三种写法对应三种粒度# count全有或全无 count var.create_instance ? 1 : 0 # for_each用 for 表达式for expression按条件过滤 for_each { for name, cfg in var.services : name cfg if cfg.enabled } # dynamic用空列表跳过嵌套块 for_each var.enable_access_logs ? [1] : []多个布尔条件先用 locals 命名化避免在 count 里堆叠长表达式locals { needs_waf var.environment production var.expose_public var.enable_waf }动态块的四个要素是 label、for_each、迭代器iterator、content迭代器可改名以避免内外层变量遮蔽。方案落在真实配置里plan 输出会验证这些结论吗五、实操复现漂移对比两种写法按四步复现上文那次事故你亲手对比两种追踪方式你用变量与 terraform_data 写出上文的 count 配置执行 terraform apply。你跑 terraform state list记录状态里的五个地址。你从 default 列表删掉 to_delete再跑 terraform plan核对输出。你把同一份数据交给 for_each重复前三步对比两次 plan。for_each 版配置把身份交给键resource terraform_data my_each { for_each toset(var.my_list) input tf_data-${each.value} }两次 plan 的差别一句话能概括count 版输出 2 to change, 1 to destroyfor_each 版只输出 1 to destroy其余四个实例 no change。同一次删除动作数差三倍差别不在资源在地址。从 count 迁移到 for_each 时地址形态整个更换旧索引地址与新键地址对不上Terraform 默认按销毁加创建处理必须显式迁移状态state migration把已有对象挂到新地址上terraform statemvterraform_data.my_count[0]terraform_data.my_each[zero]嵌套动态块用迭代器改名规避外层变量遮蔽内外层块同名时内层临时变量会覆盖外层取值错位且不报错dynamic outer_block { for_each var.outer_items content { outer_attribute outer_block.value.name dynamic inner_block { for_each outer_block.value.inner_items iterator inner content { inner_attribute inner.value.setting } } } }注意地址形态更换后不迁移状态整组资源按销毁加创建处理。跑完两组 plan选型规则能不能压缩成一句话六、总结一张表选型三件事避坑选型规则压缩成一句话实例可互换用 count身份有意义用 for_each嵌套块重复用 dynamic。你的重复场景选择理由N 个完全相同、从不单独增删的临时节点count索引稳定无需身份按名字或环境逐个创建集合会变for_each键追踪增删不波及他人一个资源内多条规则或监听器dynamic循环嵌套块不碰生命周期我踩过的三个问题按教训频率排问题根因教训删中间元素引发连锁变更索引漂移集合会变就用 for_each拿 uuid 当键每次 plan 都重建键非已知值键必须稳定且已知改写法忘迁移状态地址形态更换count 改 for_each 必跑 state mv三个元参数覆盖了 Terraform 配置里的绝大多数重复顶层多实例由 count 与 for_each 按身份二选一资源内重复结构交给 dynamic模块级重复直接复用 for_each 的键机制。下一篇用这三个元参数重构多环境 VPC 模块时再展开模块级 for_each 的输出引用七、术语速查表术语英文说明循环元参数meta-argument作用于资源块的 count、for_each 等参数索引漂移index drift列表中间增删导致数字索引整体前移资源地址resource address状态文件中定位实例的标识for 表达式for expression从集合推导新集合可带 if 过滤嵌套块nested block资源块内可重复的结构块动态块dynamic block按集合动态生成嵌套块的结构迭代器iterator动态块内可改名的临时变量状态迁移state migration用 state mv 改写状态地址的操作八、参考count 元参数for_each 元参数dynamic 动态块for 表达式terraform state mv 命令

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询