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
相关产品推荐
相关产品推荐

