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

Terraform中为count创建的VPS动态挂载磁盘和网络的问题

Terraform Hetzner Cloud批量创建VPS并挂载磁盘/网络的错误解决

问题场景

通过模块的count=3创建3台相同配置的VPS,期望每台VPS自动挂载传入的2块磁盘和2个网络,模块调用代码如下:

module "vps-test" {
  source            = "../module"
  count             = 3
  server_name       = "vpstest"
  server_image      = "debian-11"
  server_type       = "cx21"
  server_datacenter = "fsn1-dc14"
  labels            = { groups = "test_offline.test_vps" }
  server_network = {
    backend_network = {
      subnet_id = (data.terraform_remote_state.htz_network.outputs.main-subnet-id)
      ip        = "" #DHCP
    }
    custom_network = {
      subnet_id = "1867414"
      ip        = ""
    }
  }
  volumes = {
    firts_volume = {
      name = "volume1"
      size = "20"
    }
    second_volume = {
      name = "volume1"
      size = "20"
    }
  }
  hetzner_cloud_token  = var.hetzner_cloud_offline_main_api_token
  cloud_init_file_path = "../module/scripts/user.yaml"
}

当前模块代码

resource "hcloud_server" "vps" {
  count       = var.server_count
  name        = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
  image       = var.server_image
  server_type = var.server_type
  datacenter  = var.server_datacenter
  user_data   = data.template_file.ansible_user_data.rendered
  labels      = var.labels
}

resource "hcloud_volume" "volume" {
  for_each  = var.volumes
  name      = tostring(each.value["name"])
  size      = tonumber(each.value["size"])
  server_id = hcloud_server.vps.id
  automount = true
  format    = var.volume_filesystem
}

resource "hcloud_server_network" "network" {
  for_each  = var.server_network
  server_id = hcloud_server.vps.id
  subnet_id = each.value["subnet_id"]
  ip        = tostring(each.value["ip"])
}

报错信息

第一次报错(直接引用hcloud_server.vps.id)

│ Error: Missing resource instance key
│ 
│   on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│   15:   server_id = hcloud_server.vps.id
│ 
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│ 
│ For example, to correlate with indices of a referring resource, use:
│     hcloud_server.vps[count.index]
╵
╷
│ Error: Missing resource instance key
│ 
│   on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│   22:   server_id = hcloud_server.vps.id
│ 
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│ 
│ For example, to correlate with indices of a referring resource, use:
│     hcloud_server.vps[count.index]

第二次报错(改为hcloud_server.vps[count.index].id)

│ Error: Reference to "count" in non-counted context
│ 
│   on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│   15:   server_id = hcloud_server.vps[count.index].id
│ 
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
╵
╷
│ Error: Reference to "count" in non-counted context
│ 
│   on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│   22:   server_id = hcloud_server.vps[count.index].id
│ 
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.

正确实现方式

问题核心是:模块内hcloud_server用count迭代多台服务器,而hcloud_volume和hcloud_server_network用for_each迭代资源配置,两者的迭代上下文不兼容,无法直接用count.index关联。

需要重构volume和network的for_each逻辑,为每台服务器+每个挂载资源生成唯一的复合键,确保每台服务器都能对应所有传入的磁盘和网络配置。

修改后的模块代码如下:

服务器资源(保持原有逻辑)

resource "hcloud_server" "vps" {
  count       = var.server_count
  name        = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
  image       = var.server_image
  server_type = var.server_type
  datacenter  = var.server_datacenter
  user_data   = data.template_file.ansible_user_data.rendered
  labels      = var.labels
}

磁盘挂载资源(关联每台服务器)

resource "hcloud_volume" "volume" {
  # 生成复合键:服务器索引-磁盘配置key,比如"0-firts_volume"、"1-second_volume"
  for_each = {
    for idx, server in hcloud_server.vps :
    "${idx}-${volume_key}" => {
      server_id     = server.id
      volume_config = var.volumes[volume_key]
    }
    for volume_key in keys(var.volumes)
  }

  name      = tostring(each.value.volume_config["name"])
  size      = tonumber(each.value.volume_config["size"])
  server_id = each.value.server_id
  automount = true
  format    = var.volume_filesystem
}

网络挂载资源(关联每台服务器)

resource "hcloud_server_network" "network" {
  # 生成复合键:服务器索引-网络配置key,比如"0-backend_network"、"2-custom_network"
  for_each = {
    for idx, server in hcloud_server.vps :
    "${idx}-${network_key}" => {
      server_id      = server.id
      network_config = var.server_network[network_key]
    }
    for network_key in keys(var.server_network)
  }

  server_id = each.value.server_id
  subnet_id = each.value.network_config["subnet_id"]
  ip        = tostring(each.value.network_config["ip"])
}

说明

  • 通过嵌套for表达式,为每台服务器(count的每个索引)和每个挂载资源(磁盘/网络的配置key)生成唯一的复合键,确保每个服务器都会创建对应的所有磁盘和网络挂载。
  • 模块调用时的count=3需要和模块内的var.server_count保持一致,确保服务器数量匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:20:39