EC2模块动态创建EBS卷报错:无法访问字符串类型属性
Terraform创建EC2实例EBS卷参数传递失败问题
报错信息
│ Error: Unsupported attribute │ on modules/vm-deploy/main.tf line 19, in resource "aws_instance" "ec2_instance": │ 19: device_name = ebs_block_device.value.ebs_name │ │ ebs_block_device.value is "/dev/sdb" │ │ Can't access attributes on a primitive-typed value (string). ╵ │ Error: Unsupported attribute │ on modules/vm-deploy/main.tf line 19, in resource "aws_instance" "ec2_instance": │ 19: device_name = ebs_block_device.value.ebs_name │ ├──────────────── │ │ ebs_block_device.value is "100" │ │ Can't access attributes on a primitive-typed value (string).
问题原因
核心错误是**blockdisks变量类型定义与遍历逻辑不匹配**:
- 根模块中
blockdisks被定义为map(string),存储的是单个键值对(如ebs_name="/dev/sdb"、ebs_size="100"),每个值都是字符串类型。 - 模块中
dynamic "ebs_block_device"遍历该map时,ebs_block_device.value直接取到字符串("/dev/sdb"或"100"),而字符串是原始类型,无法通过.ebs_name访问属性。
相关代码
根模块variables.tf
variable "instances_subnet_1" { description = "多台虚拟机的配置对象" type = map(object({ ami = string instance_type = string private_ip = string subnet_id = string vpc_security_group_ids = list(string) blockdisks = map(string) root_size = string })) default = { "ec2-resource" = { ami = "ami-win" instance_type = "t3.large" private_ip = "10.0.109.4" subnet_id = "" vpc_security_group_ids = [""] root_size = "50" blockdisks = { "ebs_name" = "/dev/sdb" "ebs_size" = "100" } } } }
VM部署模块main.tf
resource "aws_instance" "ec2_instance" { ami = var.ami iam_instance_profile = var.iam_instance_role instance_type = var.instance_type private_ip = var.private_ip subnet_id = var.subnet_id vpc_security_group_ids = var.vpc_security_group_ids dynamic "ebs_block_device" { for_each = var.blockdisks iterator = ebs_block_device content { delete_on_termination = false encrypted = true device_name = ebs_block_device.value.ebs_name volume_size = ebs_block_device.value.ebs_size volume_type = "gp2" } } root_block_device { delete_on_termination = false encrypted = true volume_size = var.root_size volume_type = "gp2" } }
根模块main.tf
module "vm-deploy-subnet-1" { source = "./modules/vm-deploy" for_each = var.instances_subnet_1 ami = each.value.ami iam_instance_role = each.value.iam_instance_role instance_type = each.value.instance_type private_ip = each.value.private_ip subnet_id = data.aws_subnet.subnet_1.id vpc_security_group_ids = [data.aws_security_group.default.id] root_size = each.value.root_size blockdisks = each.value.blockdisks }
解决方案
调整blockdisks变量类型,使其能存储包含多属性的EBS卷对象,同时修正遍历逻辑:
1. 修改根模块variables.tf的类型定义
将blockdisks从map(string)改为list(object)(支持多块EBS卷),同时把root_size改为number(匹配volume_size的数字类型要求):
variable "instances_subnet_1" { description = "多台虚拟机的配置对象" type = map(object({ ami = string instance_type = string private_ip = string subnet_id = string vpc_security_group_ids = list(string) blockdisks = list(object({ ebs_name = string ebs_size = number })) root_size = number })) default = { "ec2-resource" = { ami = "ami-win" instance_type = "t3.large" private_ip = "10.0.109.4" subnet_id = "" vpc_security_group_ids = [""] root_size = 50 blockdisks = [ { ebs_name = "/dev/sdb" ebs_size = 100 } ] } } }
2. 修正模块中的dynamic块遍历逻辑
var.blockdisks现在是list类型,遍历每个元素(EBS卷对象)即可直接访问属性:
dynamic "ebs_block_device" { for_each = var.blockdisks content { delete_on_termination = false encrypted = true device_name = ebs_block_device.value.ebs_name volume_size = ebs_block_device.value.ebs_size volume_type = "gp2" } }
可选:用map管理EBS卷
如果希望给每个EBS卷命名标识,可将blockdisks定义为map(object):
# 根模块variables.tf中修改类型 blockdisks = map(object({ ebs_name = string ebs_size = number })) # 默认值示例 blockdisks = { "data_disk" = { ebs_name = "/dev/sdb" ebs_size = 100 } }
模块中的dynamic块遍历逻辑保持不变,for_each遍历map时value为对象类型,可正常访问.ebs_name和.ebs_size。
额外注意事项
volume_size要求为数字类型,避免用字符串传递(如"100"改为100),防止类型转换错误。- 添加多块EBS卷时,只需在
blockdisks的list或map中新增对应对象即可。
内容的提问来源于stack exchange,提问作者virtualramblings
相关产品推荐
相关产品推荐

