Terraform 0.13模块使用count时如何确保资源删除完成后再重建
问题根因
你遇到的409错误是count索引漂移和AWS IAM资源异步删除特性共同导致的:
count用数字索引标识模块/资源实例,当var.names_map的元素顺序、数量发生变化时,索引对应的实例地址会发生漂移。比如原列表有[A,B,C]三个元素对应索引0/1/2,删除B后原C对应的索引会从2变成1,Terraform会判定需要销毁旧索引1、2对应的资源,同时创建新索引1对应的资源。- AWS IAM角色的删除是异步操作,删除请求提交后需要数秒才会在全局生效,此时并发发起同名角色的创建请求就会触发实体已存在的409错误,第二次执行apply时旧资源已经删除完成,所以能执行成功。
最优解决方案:用for_each替代count
这是从根源避免索引漂移的方案,for_each用自定义的唯一键标识实例,不会因为列表顺序、其他元素增删触发无关实例的重建。
修改模块调用代码如下:
module "service" { // 用name作为唯一键标识每个实例 for_each = { for item in var.names_map : item.name => item } source = "../../modules/service" name = each.value.name // 其他变量保持不变 }
调整后每个模块实例的标识为module.service["角色名"],只要角色名不变,无论names_map如何调整,对应实例都不会触发销毁重建,自然不会出现并发删建的问题。
备选临时方案(不建议长期使用)
如果因历史逻辑限制无法替换为for_each,可以用以下方法规避报错:
- 执行apply时限制并行度,强制操作串行执行:
该方法会让Terraform同一时间只执行一个操作,确保删除完成后再执行创建,缺点是资源量大时执行速度会明显变慢。terraform apply -parallelism=1 - 给IAM角色添加删除等待逻辑,适配AWS IAM的最终一致性:
在service模块中添加等待资源,确保删除完成后再发起创建请求:resource "time_sleep" "wait_iam_delete" { create_duration = "10s" triggers = { role_name = var.name } } resource "aws_iam_role" "ecs_task_execution_role" { name = var.name assume_role_policy = data.aws_iam_policy_document.ecs_task_assume_role_policy_document.json depends_on = [time_sleep.wait_iam_delete] }
注意:不要给该IAM角色添加
create_before_destroy生命周期规则,该规则会先创建新资源再删除旧资源,同名场景下会百分百触发409错误。
内容的提问来源于stack exchange,提问作者irregular
相关产品推荐
相关产品推荐

