如何通过Terraform向Azure私有AI Search发起REST调用创建数据源?
问题描述
现有Terraform代码可创建禁用公网访问、绑定私有端点的Azure AI Search服务,该服务与存储待索引数据的CosmosDB Mongo资源处于同一虚拟网络和子网。由于hashicorp/azurerm provider暂不支持创建Azure Search的索引/索引器/数据源,使用mastercard/restapi provider通过REST API实现该功能。
当Azure AI Search和CosmosDB处于公网可访问状态时,代码可正常创建数据源;但两者切换为私有资源(仅通过私有端点访问)后,创建restapi_object时出现报错:
│ Error: Post "example-search/datasources?api-version=2024-05-01-Preview": unsupported protocol scheme "" │ │ with module.main.module.az-search.restapi_object.create_product_datasource, │ on ../../modules/az-search/main.tf line 52, in resource "restapi_object" "create_product_datasource": │ 52: resource "restapi_object" "create_product_datasource" {
相关代码片段:
providers.tf
provider "restapi" { uri = "https://example-search.search.windows.net" write_returns_object = true debug = true headers = { "api-key" = module.az-search.azure_search_api_key "Content-Type" = "application/json" } create_method = "POST" update_method = "PUT" destroy_method = "DELETE" }
az-search/main.tf
... # Create the Datasource for the Product Collection in DB resource "restapi_object" "create_product_datasource" { path = "/datasources" query_string = "api-version=2024-05-01-Preview" data = jsonencode(local.product_datasource_json) id_attribute = "name" } locals { product_datasource_json = { description = "Links Azure Search with the Product Collection within CosmosDB" type = "cosmosdb" subtype = "MongoDb" credentials = { connectionString = "AccountEndpoint=https://${azurerm_search_service.search.name}.documents.azure.com:443/;AccountKey=${var.cosmosdb_readonly_key};Database=DB;ApiKind=MongoDB" } container = { name = "Product" query = null } name = "product-datasource" identity = null } }
原因分析
- 域名解析失败:私有端点模式下,Azure Search的公共域名会被解析到VNet内部的私有IP。如果Terraform运行环境(如本地机器)不在该VNet内且未通过VPN/ExpressRoute连接,将无法解析该域名,导致
restapiprovider无法构造完整的请求URL,进而丢失协议前缀(https://),触发报错。 - REST API访问限制:Azure Search禁用公网访问后,仅允许来自VNet内部的请求,外部环境直接调用公共域名的REST API会被拒绝,间接导致请求URL构造异常。
解决方案
方案1:让Terraform运行环境接入目标VNet
- 将Terraform部署在目标VNet内的虚拟机、容器或Azure Cloud Shell(需确保Cloud Shell所在网络能访问私有端点),确保运行环境能解析Azure Search的私有域名并发起合法请求。
- 临时测试可在本地
hosts文件中手动映射Azure Search的私有IP与公共域名(生产环境不推荐,IP可能变动)。
方案2:替换restapi provider,使用Azure CLI或ARM模板
方式A:用null_resource配合Azure CLI
利用Azure CLI的私有端点访问能力,直接调用命令创建数据源:
resource "null_resource" "create_product_datasource" { provisioner "local-exec" { command = <<EOT az search datasource create \ --name product-datasource \ --service-name ${azurerm_search_service.search.name} \ --resource-group ${azurerm_resource_group.rg.name} \ --type cosmosdb \ --subtype MongoDb \ --credentials '{"connectionString":"AccountEndpoint=https://${azurerm_cosmosdb_account.cosmosdb.name}.documents.azure.com:443/;AccountKey=${var.cosmosdb_readonly_key};Database=DB;ApiKind=MongoDB"}' \ --container '{"name":"Product"}' \ --description "Links Azure Search with the Product Collection within CosmosDB" EOT } depends_on = [azurerm_search_service.search, azurerm_cosmosdb_account.cosmosdb] }
注意:需确保运行Azure CLI的环境已接入VNet,且已通过
az login完成身份验证。
方式B:用ARM模板部署数据源
通过azurerm_resource_group_template_deployment资源部署ARM模板,直接创建Azure Search数据源:
resource "azurerm_resource_group_template_deployment" "search_datasource" { name = "search-datasource-deployment" resource_group_name = azurerm_resource_group.rg.name template_content = jsonencode({ "$schema" = "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#" "contentVersion" = "1.0.0.0" "resources" = [ { "type" = "Microsoft.Search/searchServices/dataSources" "apiVersion" = "2024-05-01-Preview" "name" = "${azurerm_search_service.search.name}/product-datasource" "properties" = { "description" = "Links Azure Search with the Product Collection within CosmosDB" "type" = "cosmosdb" "subtype" = "MongoDb" "credentials" = { "connectionString" = "AccountEndpoint=https://${azurerm_cosmosdb_account.cosmosdb.name}.documents.azure.com:443/;AccountKey=${var.cosmosdb_readonly_key};Database=DB;ApiKind=MongoDB" } "container" = { "name" = "Product" } } } ] }) depends_on = [azurerm_search_service.search] }
该方式直接通过Azure Resource Manager API操作,无需额外处理REST API的访问问题,只要Terraform有对应的Azure权限即可。
内容的提问来源于stack exchange,提问作者ban_ana
相关产品推荐
相关产品推荐

