Terraform加载JSON文件到自定义子模块时的排序问题如何解决?
问题根因
当前问题核心是for_each使用了动态列表的数字索引作为资源唯一标识,列表索引会随元素数量、排序变化而变动,直接导致Terraform状态绑定关系错位,和自定义子模块本身无关,该场景完全可以用自定义子模块实现。
最优解决方案:将for_each的key绑定为稳定的JSON文件名(或文件内唯一标识)
1. 代码修改
将原来按列表索引生成映射的逻辑,改为直接用JSON文件名(去掉后缀)作为映射的key,确保每个子模块实例的标识永久和文件绑定,不受文件增减、排序影响:
locals { # 遍历所有json文件,以文件名(去掉.json后缀)为key,文件解析内容为value instance_configs = { for f in fileset("./instances/", "*.json") : trimsuffix(f, ".json") => jsondecode(file("./instances/${f}")) } } module "instance" { for_each = local.instance_configs source = "./modules/instance" server_name = each.value.server_name server_dns = each.value.server_dns server_private_ip = each.value.server_private_ip server_customer = each.value.server_customer # 其余参数保持不变 }
修改后每个子模块实例的状态路径会变成module.instance["server01"]、module.instance["server02"],删除server01.json后,Terraform只会识别到server01对应的实例需要销毁,不会影响server02的状态绑定。
2. 现有生产状态迁移(针对已经部署过资源的场景)
如果当前已经有资源在运行,直接修改代码会触发Terraform判定所有资源需要重建,可通过terraform state mv命令提前迁移状态绑定关系,无需重建资源:
# 将原来按索引绑定的状态迁移到按文件名绑定的格式 terraform state mv 'module.instance["0"]' 'module.instance["server01"]' terraform state mv 'module.instance["1"]' 'module.instance["server02"]' # 其余实例按实际对应关系依次迁移即可
迁移完成后执行terraform plan验证,不会出现非预期的销毁重建操作。
备选优化方案
如果后续存在文件名需要调整的需求,可以在每个JSON配置文件内新增一个instance_id的唯一固定字段,遍历的时候用该字段作为for_each的key,灵活度更高,完全不受文件名变动影响。
内容的提问来源于stack exchange,提问作者ShaneC
相关产品推荐
相关产品推荐

