Terraform创建Azure多存储账户及容器失败问题求助
问题背景
作为Terraform新手,需要在Azure中创建2个存储账户:第一个账户需创建2个容器,第二个无需容器。当前配置无法正确创建容器,出现以下错误:
Error: Invalid index
│
│ on storageAccount.tf line 59, in resource "azurerm_storage_container" "storageBlobContainer":
│ 59: storage_account_name = azurerm_storage_account.storageAccount[each.key].name
│ ├────────────────
│ │ azurerm_storage_account.storageAccount is object with 2 attributes
│ │ each.key is "storage_account2"
│
The given key does not identify an element in this collection value.
╵
╷
│ Error: Incorrect attribute value type
│
│ on storageAccount.tf line 60, in resource "azurerm_storage_container" "storageBlobContainer":
│ 60: name = each.value
│ ├────────────────
│ │ each.value is list of string with 2 elements
│
│ Inappropriate value for attribute "name": string required.
错误原因分析
- 索引不匹配:
azurerm_storage_account.storageAccount的键是var.storageAccount中定义的map键(如d365fodev1sbconsstg),而var.storageBlobContainer的键是存储账户的实际名称(如d365consstg),两者无法对应,导致索引查找失败。 - 类型不匹配:使用
for_each = var.storageBlobContainer时,each.value是字符串列表,但azurerm_storage_container的name字段需要单个字符串,直接赋值会报错。 - 重复键覆盖:tfvars中
storageBlobContainer重复定义了d365consstg键,后面的配置会覆盖前面的,导致仅保留最后一个容器。
修复方案
步骤1:修复tfvars中的重复键问题
将同一存储账户的容器合并到一个列表中,并把var.storageAccount的键改为存储账户实际名称,简化后续引用:
location = "northeurope" resource_group_name = "finance-sandbox" storageAccount = { "d365consstg" = { name = "d365consstg" env = "sandbox" owner = "somsubhra.mukherjee" CreatedBy = "somsubhra.mukherjee" account_tier = "Standard" account_replication_type = "LRS" table_encryption_key_type = "Account" queue_encryption_key_type = "Account" infrastructure_encryption_enabled = false change_feed_enabled = false container_delete_retention_policy_days = 7 delete_retention_policy_days = 7 } "d365filesstg" = { name = "d365filesstg" env = "sandbox" owner = "somsubhra.mukherjee" CreatedBy = "somsubhra.mukherjee" account_tier = "Standard" account_replication_type = "LRS" table_encryption_key_type = "Account" queue_encryption_key_type = "Account" infrastructure_encryption_enabled = false change_feed_enabled = false container_delete_retention_policy_days = 7 delete_retention_policy_days = 7 } } storageBlobContainer = { "d365consstg" = ["azure-webjobs-hosts", "azure-webjobs-secrets", "container1"] }
步骤2:调整存储容器资源配置
将var.storageBlobContainer展开为单个容器实例的集合,确保每个容器对应唯一的Terraform资源实例:
resource "azurerm_storage_container" "storageBlobContainer" { # 展开存储账户-容器映射为单个容器的键值对,键格式为"存储账户名-容器名" for_each = { for sa_name, containers in var.storageBlobContainer : for container in containers : "${sa_name}-${container}" => { sa_name = sa_name container_name = container } } # 通过存储账户名称直接引用对应的存储账户资源 storage_account_name = azurerm_storage_account.storageAccount[each.value.sa_name].name name = each.value.container_name # 可选:设置容器访问级别,默认private container_access_type = "private" }
步骤3:(可选)保留原存储账户键的适配方案
如果不想修改var.storageAccount的键,可通过存储账户名称匹配查找对应的资源:
resource "azurerm_storage_container" "storageBlobContainer" { for_each = { for sa_name, containers in var.storageBlobContainer : for container in containers : "${sa_name}-${container}" => { sa_name = sa_name container_name = container } } # 通过存储账户名称查找对应的存储账户资源 storage_account_name = lookup( { for k, sa in azurerm_storage_account.storageAccount : sa.name => sa.name }, each.value.sa_name ) name = each.value.container_name container_access_type = "private" }
验证执行
修改完成后,执行以下命令验证配置:
terraform init terraform plan terraform apply
内容的提问来源于stack exchange,提问作者Somsubhra Mukherjee

