【问题标题】:Issues with iterating over list, or set of elements in Terraform迭代列表或 Terraform 中的一组元素的问题
【发布时间】:2019-10-15 17:54:22
【问题描述】:

我正在尝试在跨 AZ 创建的不同子网中启动 AWS 实例,使用 count 变量对子网 ID 列表进行操作,但使用不同的方法会失败并显示错误消息。

我尝试过使用 element() 和 [count.index],我使用的是 TF v12。

以下是sn-p的代码,请忽略带#(commented)的行。

resource "aws_instance" "workers" {
#count         =   length(data.terraform_remote_state.network.outputs.public_subnet_list)
count         = length(data.aws_subnet_ids.subnet_list.ids)
instance_type = var.worker_instance_type
ami           = var.k8_ami
key_name      = aws_key_pair.ssh_key.key_name
#subnet_id     = "${data.terraform_remote_state.network.outputs.public_subnet_list[count.index]}"
subnet_id = "${element(data.aws_subnet_ids.subnet_list.ids, count.index)}"
vpc_security_group_ids = [
aws_security_group.kubernetes.id
]
}

下面是两个错误sn-ps。

Error: Invalid index

on k8-cluster.tf line 85, in resource "aws_instance" "workers":
85:   subnet_id = "${data.aws_subnet_ids.subnet_list.ids[count.index]}"
|----------------
| count.index is 2
| data.aws_subnet_ids.subnet_list.ids is set of string with 4 elements

This value does not have any indices.

element() 的另一个错误:

Error: Error in function call

on k8-cluster.tf line 85, in resource "aws_instance" "workers":
85:   subnet_id = "${element(data.aws_subnet_ids.subnet_list.ids, count.index)}"
|----------------
| count.index is 3
| data.aws_subnet_ids.subnet_list.ids is set of string with 4 elements

Call to function "element" failed: cannot read elements from set of string.

【问题讨论】:

    标签: list count element terraform


    【解决方案1】:

    这里的根本问题是 data.aws_subnet_ids.subnet_list.ids 是一个 set 值,而不是一个 list 值,因此它的元素不是按特定顺序排列的,因此不能可以通过数字索引访问到列表中。

    要将其用作列表需要决定如何对元素进行排序。在这种情况下,排序似乎并不重要,因为目标只是为每个子网创建一个实例,因此将集合传递给 sort 函数应该足以对它们进行词法排序:

    resource "aws_instance" "workers" {
      count         = length(data.terraform_remote_state.network.outputs.public_subnet_list)
      instance_type = var.worker_instance_type
      ami           = var.k8_ami
      key_name      = aws_key_pair.ssh_key.key_name
      subnet_id     = sort(data.terraform_remote_state.network.outputs.public_subnet_list)[count.index]
      vpc_security_group_ids = [
        aws_security_group.kubernetes.id
      ]
    }
    

    在 Terraform 的未来版本(在编写 v0.12.0 时不可用)中计划了一个新的 for_each 功能,这将使这更简单:

    resource "aws_instance" "workers" {
      # Planned for a future Terraform release; not in v0.12.0
      for_each = data.terraform_remote_state.network.outputs.public_subnet_list
    
      instance_type = var.worker_instance_type
      ami           = var.k8_ami
      key_name      = aws_key_pair.ssh_key.key_name
      subnet_id     = each.value
      vpc_security_group_ids = [
        aws_security_group.kubernetes.id
      ]
    }
    

    在实现后使用for_each 的一个优点(除了简洁之外)还可以告诉 Terraform 通过子网 ID 字符串而不是列表中的位置来识别此资源的各个实例。这意味着将来添加新子网不会导致以后的实例“偏移”并不必要地重新创建,就像我上面的原始示例一样。

    【讨论】:

    • 谢谢!
    【解决方案2】:

    出现此问题是因为返回的数据采用“SET”形式,而元素期望输入采用“LIST”形式。

    要解决问题,您需要将其转换为列表。

    subnet_id = "${element(tolist(data.aws_subnet_ids.subnet_list.ids), count.index)}"

    【讨论】:

      【解决方案3】:

      您只需要像这样更改计数:

      count = "${length(data.aws_subnet_ids.subnet_list.ids)}"
      

      当你引用变量时,我建议你这样做:

      "${var.var_name}" 
      

      所以整个代码如下所示:

      resource "aws_instance" "workers" {
          #count         =   "${length(data.terraform_remote_state.network.outputs.public_subnet_list)}"
          count         = "${length(data.aws_subnet_ids.subnet_list.ids)}"
          instance_type = "${var.worker_instance_type}"
          ami           = "${var.k8_ami}"
          key_name      = "${aws_key_pair.ssh_key.key_name}"
          #subnet_id     = "${data.terraform_remote_state.network.outputs.public_subnet_list[count.index]}"
          subnet_id = "${element(data.aws_subnet_ids.subnet_list.ids, count.index)}"
          vpc_security_group_ids = [
          "${aws_security_group.kubernetes.id}"
          ]
      }
      

      您可以在Terraform 中查看示例。

      【讨论】:

      • 谢谢,但这仍然会给出错误Error: Error in function call ... Call to function "element" failed: cannot read elements from set of string.' 编辑:只是补充一下,这是在 TF v12 上,而不是 v11。可能是一个错误?
      • @mzs_47 也许你可以输出subnet_ids来检查它是否真的得到了子网ID。
      • 是的,它有四个元素,如果您注意到上面的错误 sn-ps,计数会有所不同,并且它提到“是一组包含 4 个元素的字符串”,为简洁起见,我刚刚粘贴我尝试的每种方法都有一个。
      • @mzs_47 我没有使用 AWS 的经验。但是从您显示的错误来看,似乎 count.index 1 还可以,而后面的则不行。如果用v11就可以了?
      • 很遗憾,我无法切换到 v11 atm,:( 我需要抽出时间来引用表达式以使其工作。不过我稍后会尝试。谢谢!
      猜你喜欢
      • 2011-04-02
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      • 2018-05-26
      相关资源
      最近更新 更多