我正在使用我的自定义模块创建ECS服务,这是for_each
循环的一部分。我想修改每个服务中的安全组,以允许来自特定服务的通信。
考虑以下ECS服务映射:
locals {
ecs_services = {
"hello-world" = {
container_image = local.ecr_repository_url_map["hello-world"]
container_port = "5050"
}
"hello-world2" = {
container_image = local.ecr_repository_url_map["hello-world2"]
container_port = "8080"
allowed_serivces = ["hello-world"]
}
}
}
下面是我的失败尝试,导致:
Error: Cycle: module.ecs_service.module.this_ecs_service_task (close), module.ecs_service.module.this_ecs_service_task.var.allowed_security_group_ids (expand), module.ecs_service.module.this_ecs_service_task.module.ecs_service_security_group.var.ingress_with_source_security_group_id (expand), module.ecs_service.module.this_ecs_service_task.module.ecs_service_security_group.aws_security_group_rule.ingress_with_source_security_group_id, module.ecs_service.module.this_ecs_service_task.module.ecs_service_security_group (close), module.ecs_service (close), module.ecs_service.var.allowed_security_group_ids (expand)
module "ecs_service" {
source = "./ecs-service"
for_each = {
for name, service in local.ecs_services : name => service
}
name = each.key
container_image = each.value.container_image
container_port = each.value.container_port
allowed_security_group_ids = [for k, v in lookup(each.value, "allowed_services", []) : module.ecs_service[v].security_group_id]
...
}
在我的脑海中,这种构造是可能的,因为资源本身实际上并不相互引用,并且可以创建一个不产生任何冲突的顺序。但很明显,Terraform有一些限制。
是否有一个我可以实现的解决方案,它不涉及为每个服务手动创建模块?
不管你在代码中犯了什么错误,你不能做你想做什么。有两个原因:
- TF将并发创建中
ecs_service
模块的所有实例,而不是连续。所以你不能在创建之前引用不存在的资源。 - map上的迭代基于字典编撰,而不是映射元素的插入顺序。在您的简单示例中,顺序与字典顺序一致,但依赖于此是稍后出现问题的完美方式。