如何通过Terraform读取多JSON文件,用for_each部署Azure Shared App Gateway?
在Azure共享应用网关通过Terraform从多JSON文件部署多应用
目录结构规划
先把每个应用的独立配置放在单独JSON文件中,目录结构示例:
terraform/ ├── apps/ │ ├── App1.json │ ├── App2.json │ └── App3.json ├── main.tf └── variables.tf
示例应用配置JSON(App1.json)
每个文件包含对应应用的完整网关配置项:
{ "name": "app1", "backend_address_pool": { "name": "app1-backend-pool", "backend_addresses": [ { "fqdn": "app1-service.example.com" } ] }, "http_settings": { "name": "app1-http-settings", "port": 80, "protocol": "Http", "cookie_based_affinity": "Disabled" }, "probe": { "name": "app1-probe", "protocol": "Http", "path": "/health", "interval": 30, "timeout": 10 }, "listener": { "name": "app1-listener", "frontend_ip_configuration_name": "appgw-frontend-ip", "frontend_port_name": "appgw-frontend-port-80", "protocol": "Http", "host_name": "app1.example.com" }, "request_routing_rule": { "name": "app1-routing-rule", "rule_type": "Basic" } }
Terraform配置实现
1. 读取并解析所有应用JSON文件
通过fileset批量获取apps/目录下的JSON文件,再用jsondecode转成Terraform可识别的对象:
locals { app_configs = { for file in fileset(path.module, "apps/*.json") : replace(basename(file), ".json", "") => jsondecode(file("${path.module}/${file}")) } }
这里用basename(file)提取文件名(去除路径),再去掉.json后缀,最终生成App1、App2作为遍历的key,方便后续关联资源。
2. 部署共享应用网关基础资源
先创建网关的共享核心资源(如果尚未存在):
resource "azurerm_resource_group" "appgw" { name = "appgw-rg" location = "eastus" } resource "azurerm_public_ip" "appgw" { name = "appgw-pip" location = azurerm_resource_group.appgw.location resource_group_name = azurerm_resource_group.appgw.name allocation_method = "Static" sku = "Standard" } resource "azurerm_application_gateway" "shared" { name = "shared-appgw" resource_group_name = azurerm_resource_group.appgw.name location = azurerm_resource_group.appgw.location sku { name = "Standard_v2" tier = "Standard_v2" capacity = 2 } frontend_ip_configuration { name = "appgw-frontend-ip" public_ip_address_id = azurerm_public_ip.appgw.id } frontend_port { name = "appgw-frontend-port-80" port = 80 } }
3. 用for_each批量创建应用专属资源
遍历local.app_configs,自动生成每个应用对应的网关组件:
后端地址池
resource "azurerm_application_gateway_backend_address_pool" "app" { for_each = local.app_configs name = each.value.backend_address_pool.name application_gateway_id = azurerm_application_gateway.shared.id backend_addresses = each.value.backend_address_pool.backend_addresses }
HTTP设置
resource "azurerm_application_gateway_http_settings" "app" { for_eeach = local.app_configs name = each.value.http_settings.name application_gateway_id = azurerm_application_gateway.shared.id port = each.value.http_settings.port protocol = each.value.http_settings.protocol cookie_based_affinity = each.value.http_settings.cookie_based_affinity pick_host_name_from_backend_address = true }
健康探针
resource "azurerm_application_gateway_probe" "app" { for_eeach = local.app_configs name = each.value.probe.name application_gateway_id = azurerm_application_gateway.shared.id protocol = each.value.probe.protocol path = each.value.probe.path interval = each.value.probe.interval timeout = each.value.probe.timeout unhealthy_threshold = 3 }
HTTP监听器
resource "azurerm_application_gateway_http_listener" "app" { for_each = local.app_configs name = each.value.listener.name application_gateway_id = azurerm_application_gateway.shared.id frontend_ip_configuration_name = each.value.listener.frontend_ip_configuration_name frontend_port_name = each.value.listener.frontend_port_name protocol = each.value.listener.protocol host_name = each.value.listener.host_name }
请求路由规则
resource "azurerm_application_gateway_request_routing_rule" "app" { for_eeach = local.app_configs name = each.value.request_routing_rule.name application_gateway_id = azurerm_application_gateway.shared.id rule_type = each.value.request_routing_rule.rule_type http_listener_name = azurerm_application_gateway_http_listener.app[each.key].name backend_address_pool_name = azurerm_application_gateway_backend_address_pool.app[each.key].name backend_http_settings_name = azurerm_application_gateway_http_settings.app[each.key].name probe_name = azurerm_application_gateway_probe.app[each.key].name }
关键注意事项
- 所有应用的网关资源名称(如监听器、后端池名称)必须唯一,避免冲突
- 如需HTTPS,只需在JSON配置中新增SSL相关字段(如
protocol: "Https"、ssl_certificate_name),并在Terraform中创建对应SSL证书资源 - 可将共享资源名称(如前端IP配置名)提取为变量,避免硬编码在JSON文件中
- 新增/删除
apps/目录下的JSON文件时,Terraform会自动检测并同步创建/销毁对应资源
内容的提问来源于stack exchange,提问作者Sagar Hiremath
相关产品推荐
相关产品推荐

