迭代列表或 Terraform 中的元素集的问题
Issues with iterating over list, or set of elements in Terraform
我尝试在子网 ID 列表上使用 count 变量在跨可用区创建的不同子网中启动 AWS 实例,但使用不同的方法失败并显示错误消息。
我已经尝试使用 element() 和 [count.index],我正在使用 TF v12。
以下是代码片段,请忽略带有#(注释)的行。
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
]
}
下面是两个错误片段。
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.
您只需要像这样更改计数:
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 中查看示例。
这里的根本问题是 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 字符串而不是在列表中的位置来识别此资源的各个实例.这意味着将来添加新的子网不会导致以后的实例 "offset" 和不必要的重新创建,就像我上面的原始示例一样。
发生此问题是因为返回的数据采用 "SET" 形式,而元素期望输入采用 "LIST".
形式
要解决此问题,您需要将其转换为列表。
subnet_id = "${element(tolist(data.aws_subnet_ids.subnet_list.ids), count.index)}"
我尝试在子网 ID 列表上使用 count 变量在跨可用区创建的不同子网中启动 AWS 实例,但使用不同的方法失败并显示错误消息。
我已经尝试使用 element() 和 [count.index],我正在使用 TF v12。
以下是代码片段,请忽略带有#(注释)的行。
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
]
}
下面是两个错误片段。
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.
您只需要像这样更改计数:
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 中查看示例。
这里的根本问题是 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 字符串而不是在列表中的位置来识别此资源的各个实例.这意味着将来添加新的子网不会导致以后的实例 "offset" 和不必要的重新创建,就像我上面的原始示例一样。
发生此问题是因为返回的数据采用 "SET" 形式,而元素期望输入采用 "LIST".
形式要解决此问题,您需要将其转换为列表。
subnet_id = "${element(tolist(data.aws_subnet_ids.subnet_list.ids), count.index)}"