You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform部署OpenStack多实例并挂载多附加磁盘问题求助

问题:Terraform部署OpenStack实例时多附加磁盘挂载失败

我尝试通过Terraform在OpenStack中部署多个云实例,并为这些实例挂载多块附加磁盘,但当前配置仅能处理第一块附加磁盘,尝试遍历磁盘列表时配置失败,仅配置单块附加磁盘时可正常运行。

原配置代码

variable "instances" {
  description = "要部署的实例"
  type = map(object({
    name             = string
    image            = string
    flavor           = string
    volume_size      = number
    security_groups  = list(string)
    network          = string
    keypair_name     = string
    floating_ip_pool = string
    tags             = list(string)
    additional_disks = list(object({
      disk        = string
      volume_size = number
    }))
  }))
}

instances = {
  "Websrv01" = {
    name             = "websrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh-pub"
    floating_ip_pool = "public"
    tags             = ["general", "webserver"]
    additional_disks = []
  },
  "dbsrv01" = {
    name             = "dbsrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh-pub"
    floating_ip_pool = "public"
    tags             = ["general", "dbserver"]
    additional_disks = [
      { disk = "db_data", volume_size = 30 },
      { disk = "db_log", volume_size = 10 }
    ]
  }
}

resource "openstack_compute_instance_v2" "instances" {
  for_each = var.instances

  name            = each.value.name
  flavor_id       = data.openstack_compute_flavor_v2.flavor[each.key].id
  key_pair        = each.value.keypair_name
  security_groups = each.value.security_groups

  ## 系统盘
  block_device {
    uuid                  = data.openstack_images_image_v2.image[each.key].id
    source_type           = "image"
    volume_size           = each.value.volume_size
    boot_index            = 0
    destination_type      = "volume"
    delete_on_termination = true
  }
 
  lifecycle {
    prevent_destroy = true
  }

  network {
    name = each.value.network
  }

  tags = each.value.tags
}

## 按需申请浮动IP
resource "openstack_networking_floatingip_v2" "floating_ip" {
  for_each = { for k, v in var.instances : k => v if v.floating_ip_pool != "" }

  pool = each.value.floating_ip_pool
}

## 绑定浮动IP到实例
resource "openstack_compute_floatingip_associate_v2" "associate" {
  for_each = openstack_networking_floatingip_v2.floating_ip

  instance_id = openstack_compute_instance_v2.instances[each.key].id
  floating_ip = each.value.address
}

## 附加磁盘
resource "openstack_blockstorage_volume_v3" "additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  name                 = "${each.key}-${each.value[0].disk}"
  size                 = each.value[0].volume_size
  enable_online_resize = true
}

## 挂载附加磁盘到实例
resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  instance_id = openstack_compute_instance_v2.instances[each.key].id
  volume_id   = openstack_blockstorage_volume_v3.additional_disks[each.key].id
}

问题根源

原配置中,openstack_blockstorage_volume_v3.additional_disks和openstack_compute_volume_attach_v2.attach_additional_disks的for_each是按实例分组,每个实例对应一组磁盘列表,后续代码中直接取each.value[0]只处理了列表中第一块磁盘,导致多磁盘场景下只有第一块被创建和挂载。

要实现多磁盘处理,需要将每个磁盘作为独立的资源实例,因此需要构造一个包含实例ID-磁盘名称的唯一键值对集合,确保每块磁盘都能生成对应的资源。

修正后的配置

1. 创建附加磁盘

resource "openstack_blockstorage_volume_v3" "additional_disks" {
  # 构造包含实例和磁盘的唯一映射:key格式为"实例名-磁盘名"
  for_each = flatten([
    for instance_name, instance in var.instances : [
      for disk in instance.additional_disks : {
        key         = "${instance_name}-${disk.disk}"
        instance_id = instance_name
        disk_name   = disk.disk
        size        = disk.volume_size
      }
    ]
  ])

  name                 = each.value.key
  size                 = each.value.size
  enable_online_resize = true
}

2. 挂载附加磁盘到实例

resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
  # 复用磁盘资源的for_each,确保每块磁盘对应一个挂载资源
  for_each = openstack_blockstorage_volume_v3.additional_disks

  instance_id = openstack_compute_instance_v2.instances[each.value.instance_id].id
  volume_id   = each.value.id
}

说明

  • 通过flatten和嵌套循环,将每个实例的每块磁盘转换为独立的键值对,确保for_each为每块磁盘生成单独的资源实例。
  • 磁盘名称使用实例名-磁盘名格式,保证全局唯一。
  • 挂载资源直接复用磁盘资源的for_each,自动关联对应的实例和磁盘,无需手动指定索引。

内容的提问来源于stack exchange,提问作者Eddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:54:52