Terraform AWS subnet_id 列表被视为 ec2 实例的单值字符串

Posted

技术标签:

【中文标题】Terraform AWS subnet_id 列表被视为 ec2 实例的单值字符串【英文标题】:Terraform AWS subnet_id list is treated as single value string for ec2 instance 【发布时间】:2019-09-26 18:59:35 【问题描述】:

我有创建 VPC 的代码,其中有 2 个私有子网、2xec2 私有实例和公共堡垒。

ec2 代码使用 VPC 模块 subnet_ids 的 output.tf。由于有 2 个私有子网,因此生成了 2 个子网 ID。当这些生成的子网 ID 被输入到 ec2 实例而不是一个子网 ID 时,它会同时输入 2 个子网 ID 作为单个值。

结果 terraform 找不到该子网 ID 值,创建失败。

错误: 子网 ID 'subnet-0*************,subnet-0*************' 不存在

编辑子网* vpc.tf

private_subnets     = "10.10.20.#/#,10.10.20.#/#"

instanceec2.tf

subnet_id           = "$module.vpc.private_subnets"

以下是模块:

vpc_main.tf

// Private subnet/s
resource "aws_subnet" "private" 
  vpc_id            = "$aws_vpc.vpc.id"
  cidr_block        = "$element(split(",", var.private_subnets), count.index)"
  availability_zone = "$element(split(",", var.azs), count.index)"
  count             = "$length(split(",", var.private_subnets))"

  tags 
    Name        = "$var.name-private-$element(split(",", var.azs), count.index)"
    Team        = "$var.team"
    Environment = "$var.environment"
    Service     = "$var.service"
    Product     = "$var.product"
    Owner       = "$var.owner"
    Description = "$var.description"
    managed_by  = "terraform"
  


resource "aws_route_table" "private" 
  vpc_id = "$aws_vpc.vpc.id"
  count  = "$length(split(",", var.private_subnets))"

  tags 
    Name        = "$var.name-private-$element(split(",", var.azs), count.index)"
    Team        = "$var.team"
    Environment = "$var.environment"
    Service     = "$var.service"
    Product     = "$var.product"
    Owner       = "$var.owner"
    Description = "$var.description"
    managed_by  = "terraform"
  


resource "aws_route_table_association" "private" 
  subnet_id      = "$element(aws_subnet.private.*.id, count.index)"
  route_table_id = "$element(aws_route_table.private.*.id, count.index)"
  count          = "$length(split(",", var.private_subnets))"

``````


vpc_outputs.tf

```````

output "private_subnets" 
  value = "$join(",", aws_subnet.private.*.id)"

期望值只有一个子网ID作为值:

错误:提供 2 个子网 ID 作为一个值。

aws_instance.ec2-instance[0]:发生 1 个错误:

aws_instance.ec2-instance.0:启动源实例时出错:InvalidSubnetID.NotFound:子网 ID 'subnet-0**********,subnet-0********* **' 不存在

【问题讨论】:

错误是否来自 terraform plan -out vpc-main.tf?如果不是,该命令提供什么输出? 错误来自 terraform apply。该命令提供私有子网 ID。 【参考方案1】:

您将在输出变量中加入子网 ID:

output "private_subnets" 
  value = "$join(",", aws_subnet.private.*.id)"

当您从 instanceec2.tf 访问此输出值时,您将只会收到此连接的 ID 字符串。 因此,您必须再次像以前一样删除收到的值,并使用您的 ec2 资源的计数索引访问相应的个人 ID:

resource "aws_instance" "default" 
    count     = "$length(split(",", module.vpc.private_subnets))"
    subnet_id = "$element(split(",", module.vpc.private_subnets), count.index)"
    ....
    

这应该可以解决你的问题。

或者,您也可以将子网 ID 直接输出为列表:

output "private_subnets" 
  description = "The IDs of the private subnets as list"
  value       = ["$aws_subnet.private.*.id"]


然后通过以下方式访问它们:

subnet_id = "$element(module.vpc.private_subnets, count.index)"

【讨论】:

count.index 不起作用,因为 outputs.tf 属于 VPC 模块,我在不同的模块 ec2.tf 中使用该输出。 当然可以,但我认为您也会在 EC2 实例资源定义中使用 count = ...。您还可以为大于 ID 数组长度的实例指定计数。例如,计数为 3 时,Terraform 会将子网 0 分配给实例 0,子网 1 分配给实例 1,子网 0 再次分配给实例 3,依此类推。 "Join" 和 "Split" 对我有用,'list' 和 'element' 方式不是。非常感谢!【参考方案2】:

由于您已“加入”结果,如果您只需要一个子网值,则必须再次拆分。 类似的东西:

element(split(",", var.private_subnets), 0) 

【讨论】:

我想给多个子网,但作为一个值。我有 2 个子网,其中 ec2 实例必须存在。它也应该是动态的,不指定 0、1 等。 每个 ec2 实例只能驻留在一个子网中。它不能跨越多个子网。 是有道理的,那么如何在位于不同 AZ 的实例之间进行同步呢?两个 AZ 是否具有相同的 VPC_ids、subnet_ids 和 instance_id 以及相同的实例。 2AZ 是否意味着克隆?所有属性都一样??非常感谢您的回答。 实例之间的同步是什么意思?

以上是关于Terraform AWS subnet_id 列表被视为 ec2 实例的单值字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 terraform 在非默认 VPC 中创建 AWS RDS 实例

将地图转换为terraform aws_autoscaling_group的列表

Terraform:从对象列表中检索值

不支持的参数。此处不应使用名为“subnet_id”的参数

如何使用Terraform将虚拟网络添加到api管理中?

Terraform aws - 无法使用 terraform 脚本创建 AWS SFTP 服务器