通过Terraform创建云主机时如何处理多个云盘挂载的问题
2024-08-23 10:20:41 作者:佚名 在某些业务场景下,通过Terraform创建云主机时,一个机器可能需要挂载多个云盘。一般来说,云厂商会单独创建云主机和云硬盘,然后通过attachment的资源去挂载。因此,我们的模板大致如下:
resource "tencentcloud_instance" "basic" {
instance_name = var.instance_name
password = "xxx"
}
resource "tencentcloud_cbs_storage" "storage" {
for_each = var.data_disks
storage_name = each.key
storage_type = each.value.disk_type
storage_Size = each.value.size
}
resource "tencentcloud_cbs_storage_attachment" "attachment" {
count = length(tencentcloud_cbs_storage.storage)
storage_id = element(values(tencentcloud_cbs_storage.storage)[*].id, count.index)
instance_id = tencentcloud_instance.basic.id
}
variable "data_disks" {
type = map(object({
disk_type = string
size = number
}))
description = "Instance Data Disks"
default = {}
}
这个模板已经使用了很长时间,完全满足多盘的需求,并且具有一定的灵活性。然而,随着全方位降本的需求以及服务优化等措施,业务方评估可以考虑减少云盘数量。由于机型的特殊性,机器也不能回收重新创建。
由于之前一直没有减盘的场景,因此一直没有关注到减盘的问题。直到最近业务方评估需要减盘,我们发现在减盘时盘的attachment会销毁并重新创建,腾讯云这个资源的操作会伴随unmount动作,导致减盘之后盘没有被挂载上。
这个现象超出了我的预期。分析Terraform的日志后,发现attachment的索引是index,减盘时索引会重新计算,导致attachment资源被销毁并重建,从而导致云盘被卸载。
原因明确了,接下来就可以解决了。我们可以使用for_each来解决这个问题,如下所示:
resource "tencentcloud_cbs_storage_attachment" "attachment" {
for_each = toset(values(tencentcloud_cbs_storage.storage)[*].id)
storage_id = each.key
instance_id = tencentcloud_instance.foo.id
}
然而,事情往往不那么顺利:
│ Error: Invalid for_each argument
│
│ on main.tf line 61, in resource "tencentcloud_cbs_storage_attachment" "attachment":
│ 61: for_each = toset(values(tencentcloud_cbs_storage.storage)[*].id)
│ ├────────────────
│ │ tencentcloud_cbs_storage.storage is object with 6 attributes
│
│ The "for_each" value depends on resource attributes that cannot be
│ determined until apply, so Terraform cannot predict how many instances will
│ be created. To work around this, use the -target argument to first apply
│ only the resources that the for_each depends on.
在Terraform论坛上发现了一个issue,简而言之,就是for_each要求他的map key必须是已知明确的值,不能是依赖其他资源的值,因此会出现上述错误。了解到这个限制后,我们调整了模板:
resource "tencentcloud_cbs_storage_attachment" "attachment" {
for_each = var.data_disks
storage_id = tencentcloud_cbs_storage.storage[each.key].id
instance_id = tencentcloud_instance.basic.id
}
终于圆满解决了问题,新创建的实例可以使用新的模板。但是存量的实例无法调整,因此仍然需要忍受盘重新挂载的问题。