部署 Azure 資源時使用連結和巢狀的範本

若要部署複雜的解決方案,可以將您的 Azure Resource Manager 範本 (ARM 範本) 分為多個相關的範本,然後再透過主要範本一起進行部署。 相關範本可以是內嵌於主要範本中的個別檔案或範本語法。 本文使用連結範本一詞來指涉透過來自主要範本之連結,進行參考的其他範本檔案。 而巢狀範本一詞則用來指內嵌於主要範本中的範本語法。

若為小型至中型的解決方案,單一範本會比較容易了解和維護。 您可以在單一檔案中看到所有的資源和值。 針對進階案例,連結範本可供將解決方案拆解為目標元件。 您可在其他案例中,輕鬆地重複使用這些範本。

如需教學課程,請參閱教學課程:部署連結範本

注意

若為連結或巢狀範本,只能將部署模式設為累加。 不過主要範本可在完整模式中進行部署。 若您在完整模式中部署主要範本,且連結或巢狀範本的目標為相同的資源群組,則完整模式部署評估會包含部署於連結或巢狀範本中的資源。 合併了部署於主要範本以及連結或巢狀範本的資源集合,會與資源群組中現有的資源進行比較。 未包含於此合併集合的任何資源都會刪除。

若連結或巢狀範本以不同的資源群組為目標,則該部署會使用累加模式。

提示

我們建議使用 Bicep,因為其提供的功能與 ARM 範本相同,而且語法更易於使用。 若要深入了解,請參閱模組

巢狀範本

若要巢狀處理範本,請對主要範本新增部署資源。 在 template 屬性中,請指定範本語法。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          <nested-template-syntax>
        }
      }
    }
  ],
  "outputs": {
  }
}

下列範例會透過巢狀範本,部署儲存體帳戶。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Storage/storageAccounts",
              "apiVersion": "2021-04-01",
              "name": "[parameters('storageAccountName')]",
              "location": "West US",
              "sku": {
                "name": "Standard_LRS"
              },
              "kind": "StorageV2"
            }
          ]
        }
      }
    }
  ],
  "outputs": {
  }
}

巢狀範本中的運算式評估範圍

使用巢狀範本時,您可指定是否要在父範本或巢狀範本的範圍內評估範本運算式。 範圍會決定參數、變數以及函式 (如 resourceGroup訂閱) 的解析方式。

您可以透過 expressionEvaluationOptions 屬性,設定範圍。 根據預設,expressionEvaluationOptions 屬性會設定為 outer,其代表使用父範本範圍。 將值設為 inner,可使運算式在巢狀範本的範圍內進行評估。

{
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2021-04-01",
  "name": "nestedTemplate1",
  "properties": {
    "expressionEvaluationOptions": {
      "scope": "inner"
    },
  ...

注意

當範圍設定為 outer 時,即無法針對已部署在巢狀範本內的資源,在巢狀範本中的輸出區段使用 reference 函式。 若要傳回部署在巢狀範本中資源的值,請使用 inner 範圍,或將您的巢狀範本轉換為連結範本。

下列範本示範如何根據範圍,解析範本運算式。 其包含名為 exampleVar 的變數,且父範本以及巢狀範本中都定義了該變數。 此外,還會傳回該變數的值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "variables": {
    "exampleVar": "from parent template"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "nestedTemplate1",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "variables": {
            "exampleVar": "from nested template"
          },
          "resources": [
          ],
          "outputs": {
            "testVar": {
              "type": "string",
              "value": "[variables('exampleVar')]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
    "messageFromLinkedTemplate": {
      "type": "string",
      "value": "[reference('nestedTemplate1').outputs.testVar.value]"
    }
  }
}

exampleVar 的值會根據 expressionEvaluationOptions 中的 scope屬性值而有所變更。 下表顯示兩個範圍的結果。

評估範圍 輸出
inner 來自巢狀範本
外部 (或預設) 來自父範本

下列範例部署了 SQL 伺服器,並擷取金鑰保存庫祕密,以供密碼使用。 由於該範圍會動態建立金鑰保存庫識別碼 (請參見外部範本 parameters 中的 adminPassword.reference.keyVault),並將其以參數傳遞到巢狀範本,所以會設定為 inner

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "The location where the resources will be deployed."
      }
    },
    "vaultName": {
      "type": "string",
      "metadata": {
        "description": "The name of the keyvault that contains the secret."
      }
    },
    "secretName": {
      "type": "string",
      "metadata": {
        "description": "The name of the secret."
      }
    },
    "vaultResourceGroupName": {
      "type": "string",
      "metadata": {
        "description": "The name of the resource group that contains the keyvault."
      }
    },
    "vaultSubscription": {
      "type": "string",
      "defaultValue": "[subscription().subscriptionId]",
      "metadata": {
        "description": "The name of the subscription that contains the keyvault."
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "adminLogin": {
            "value": "ghuser"
          },
          "adminPassword": {
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminLogin": {
              "type": "string"
            },
            "adminPassword": {
              "type": "securestring"
            },
            "location": {
              "type": "string"
            }
          },
          "variables": {
            "sqlServerName": "[concat('sql-', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2021-02-01-preview",
              "name": "[variables('sqlServerName')]",
              "location": "[parameters('location')]",
              "properties": {
                "administratorLogin": "[parameters('adminLogin')]",
                "administratorLoginPassword": "[parameters('adminPassword')]"
              }
            }
          ],
          "outputs": {
            "sqlFQDN": {
              "type": "string",
              "value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
  }
}

在巢狀範本中使用安全參數時,請務必小心。 當您將範圍設定為外部時,安全值會以純文字儲存在部署歷程記錄中。 而使用者在檢視部署歷程記錄中的範本時,就會看到這些安全值。 因此,請改為使用內部範圍,或將需要安全值的資源加入父範本。

下列摘錄顯示安全值和不安全的值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "adminPasswordOrKey": {
      "type": "securestring",
      "metadata": {
        "description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
      }
    }
  },
  ...
  "resources": [
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2021-04-01",
      "name": "mainTemplate",
      "properties": {
        ...
        "osProfile": {
          "computerName": "mainTemplate",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPasswordOrKey')]" // Yes, secure because resource is in parent template
        }
      }
    },
    {
      "name": "outer",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "outer"
        },
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Compute/virtualMachines",
              "apiVersion": "2021-04-01",
              "name": "outer",
              "properties": {
                ...
                "osProfile": {
                  "computerName": "outer",
                  "adminUsername": "[parameters('adminUsername')]",
                  "adminPassword": "[parameters('adminPasswordOrKey')]" // No, not secure because resource is in nested template with outer scope
                }
              }
            }
          ]
        }
      }
    },
    {
      "name": "inner",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "adminPasswordOrKey": {
              "value": "[parameters('adminPasswordOrKey')]"
          },
          "adminUsername": {
              "value": "[parameters('adminUsername')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminUsername": {
              "type": "string",
              "metadata": {
                "description": "Username for the Virtual Machine."
              }
            },
            "adminPasswordOrKey": {
              "type": "securestring",
              "metadata": {
                "description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
              }
            }
          },
          "resources": [
            {
              "type": "Microsoft.Compute/virtualMachines",
              "apiVersion": "2021-04-01",
              "name": "inner",
              "properties": {
                ...
                "osProfile": {
                  "computerName": "inner",
                  "adminUsername": "[parameters('adminUsername')]",
                  "adminPassword": "[parameters('adminPasswordOrKey')]" // Yes, secure because resource is in nested template and scope is inner
                }
              }
            }
          ]
        }
      }
    }
  ]
}

連結的範本

若要連結範本,請對主要範本新增部署資源。 請在 templateLink 屬性中,指定要包含的範本 URL。 下列範例會連結至儲存體帳戶中的範本。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
          "contentVersion":"1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
  }
}

參考連結範本時,uri 的值不能是本機檔案或只能在區域網路上使用的檔案。 Azure Resource Manager 必須能夠存取範本。 提供可下載為 HTTP 或 HTTPS 的 URI 值。

您可以使用包含 HTTP 或 HTTPS 的參數來參考範本。 例如,常見模式是使用 _artifactsLocation 參數。 您可以使用類似如下的運算式,設定連結範本:

"uri": "[concat(parameters('_artifactsLocation'), '/shared/os-disk-parts-md.json', parameters('_artifactsLocationSasToken'))]"

如果要連結至 GitHub 中的範本,請使用原始 URL。 連結的格式為:https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json。 若要取得原始連結,請選取 [原始]。

Select raw URL

注意

若要針對儲存在私人 GitHub 存放庫中的連結範本來部署範本或參考,請參閱建立自訂和安全 Azure 入口網站供應項目中記載的自訂解決方案。 您可以建立 Azure 函數,以從 Azure Key Vault 提取 GitHub 權杖。

連結範本的參數

您可以在外部檔案或內嵌中,為連結範本提供參數。 提供外部參數檔案時,請使用 parametersLink 屬性:

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "linkedTemplate",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
        "contentVersion": "1.0.0.0"
      },
      "parametersLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.parameters.json",
        "contentVersion": "1.0.0.0"
      }
    }
  }
]

若要以內嵌方式傳遞參數值,請使用 parameters 屬性。

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "linkedTemplate",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
        "contentVersion": "1.0.0.0"
      },
      "parameters": {
        "storageAccountName": {
          "value": "[parameters('storageAccountName')]"
        }
      }
    }
  }
]

您無法對參數檔案同時使用內嵌參數和連結。 同時指定 parametersLinkparameters 時,部署將會失敗並發生錯誤。

使用連結範本的相對路徑

Microsoft.Resources/deploymentsrelativePath 屬性能讓撰寫連結範本變得更加輕鬆。 此屬性可用來將遠端連結範本部署至相對於父系的位置。 此功能需要將所有的範本檔案都暫存於遠端 URI,並於該處提供使用,例如 GitHub 或 Azure 儲存體帳戶。 使用來自 Azure PowerShell 或 Azure CLI 的 URI,呼叫主要範本時,子部署 URI 會組合父系和 relativePath。

注意

建立 templateSpec 時,relativePath 屬性所參考的所有範本,都會由 Azure PowerShell 或 Azure CLI 在 templateSpec 資源中進行封裝, 而無須暫存檔案。 如需詳細資訊,請參閱使用連結範本建立範本規格

假設資料夾結構如下:

resource manager linked template relative path

下列範本展示 mainTemplate.json 如何部署上圖所示的 nestedChild.json

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "childLinked",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "relativePath": "children/nestedChild.json"
        }
      }
    }
  ],
  "outputs": {}
}

在下列部署中,上述範本中連結範本的 URI 為 https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/linked-template-relpath/children/nestedChild.json

New-AzResourceGroupDeployment `
  -Name linkedTemplateWithRelativePath `
  -ResourceGroupName "myResourceGroup" `
  -TemplateUri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/linked-template-relpath/mainTemplate.json"

若要透過儲存於 Azure 儲存體帳戶中的相對路徑,來部署連結範本,請使用QueryString/query-string 參數,指定要搭配 TemplateUri 參數使用的 SAS 權杖。 只有 Azure CLI 2.18 版以上,以及 Azure PowerShell 5.4 版以上才支援此參數。

New-AzResourceGroupDeployment `
  -Name linkedTemplateWithRelativePath `
  -ResourceGroupName "myResourceGroup" `
  -TemplateUri "https://stage20210126.blob.core.windows.net/template-staging/mainTemplate.json" `
  -QueryString $sasToken

請確認 QueryString 中沒有前置詞 "?"。 為部署組合 URI 時,會新增一個部署。

範本規格

您可以建立範本規格,將主要範本及其連結範本封裝進您可以部署的單一實體,而不用在可存取的端點上保有您的連結範本。 範本規格是您 Azure 訂閱中的資源, 可讓您輕鬆安全地與組織中的使用者共用範本。 您可以使用 Azure 角色型存取控制 (Azure RBAC),授與範本規格的存取權。此功能目前為預覽版。

如需詳細資訊,請參閱

相依性

如同其他資源類型一般,您可以在巢狀/連結範本之間設定相依性。 若必須先部署某個巢狀/連結範本中的資源後,才能部署第二個巢狀/連結範本中的資源,則請將第二個範本設定為相依於第一個範本。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate1",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'firstresources.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate2",
      "dependsOn": [
        "[resourceId('Microsoft.Resources/deployments', 'linkedTemplate1')]"
      ],
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'secondresources.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ]
}

contentVersion

您無須將 contentVersion 屬性提供給 templateLinkparametersLink 屬性。 若您未提供 contentVersion,則會部署目前版本的範本。 如果您提供內容版本值,它必須符合所連結範本中的版本;否則,部署會因為錯誤而失敗。

先前的範例示範了範本連結的硬式編碼 URL 值。 這種方法可能適用於簡單的範本,但不適合大型的模組化範本。 不過,您可以建立一個儲存主要範本之基底 URL 的靜態變數,然後再從該基底 URL 連結動態建立連結的範本之 URL。 此方法的好處是您可以輕鬆地移動範本或建立分支範本,因為您只需變更主要範本中的靜態變數即可。 主要範本會於整個分解的範本傳遞正確的 URI。

下列範例示範如何使用基底 URL,為連結範本建立兩個 URL (sharedTemplateUrlvmTemplateUrl)。

"variables": {
  "templateBaseUrl": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/application-workloads/postgre/postgresql-on-ubuntu/",
  "sharedTemplateUrl": "[uri(variables('templateBaseUrl'), 'shared-resources.json')]",
  "vmTemplateUrl": "[uri(variables('templateBaseUrl'), 'database-2disk-resources.json')]"
}

您也可以使用 deployment() 取得目前範本的基底 URL,用來取得相同位置中其他範本的 URL。 如果您的範本位置變更,或您想要避免在範本檔案中使用硬式編碼 URL,這十分實用。 只有使用 URL 連結到遠端範本時,才會傳回 templateLink 屬性。 如果您使用本機範本,就無法使用該屬性。

"variables": {
  "sharedTemplateUrl": "[uri(deployment().properties.templateLink.uri, 'shared-resources.json')]"
}

最後,您可在 templateLink 屬性的 uri 屬性中,使用變數。

"templateLink": {
 "uri": "[variables('sharedTemplateUrl')]",
 "contentVersion":"1.0.0.0"
}

使用複本

若要使用巢狀範本建立某資源的多個執行個體,請在 Microsoft.Resources/deployments 資源層級,新增 copy 元素。 或者,可以在範圍是 inner 時,在巢狀範本中新增複本。

下列範例範本將示範如何搭配使用 copy 與巢狀範本。

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "[concat('nestedTemplate', copyIndex())]",
    // yes, copy works here
    "copy": {
      "name": "storagecopy",
      "count": 2
    },
    "properties": {
      "mode": "Incremental",
      "expressionEvaluationOptions": {
        "scope": "inner"
      },
      "template": {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "resources": [
          {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2021-04-01",
            "name": "[concat(variables('storageName'), copyIndex())]",
            "location": "West US",
            "sku": {
              "name": "Standard_LRS"
            },
            "kind": "StorageV2"
            // Copy works here when scope is inner
            // But, when scope is default or outer, you get an error
            // "copy": {
            //   "name": "storagecopy",
            //   "count": 2
            // }
          }
        ]
      }
    }
  }
]

從連結的範本取得值

若要從連結的範本取得輸出值,請使用如下語法擷取屬性值:"[reference('deploymentName').outputs.propertyName.value]"

從連結範本取得輸出屬性時,屬性名稱不得包含虛線。

下列範例會示範如何參考連結的範本,並擷取輸出值。 連結的範本會傳回簡單的訊息。 首先是連結範本:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [],
  "outputs": {
    "greetingMessage": {
      "value": "Hello World",
      "type": "string"
    }
  }
}

主要範本會部署連結的範本,並取得傳回的值。 請注意,它會依名稱參考部署資源,並使用連結的範本所傳回之屬性的名稱。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'helloworld.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
    "messageFromLinkedTemplate": {
      "type": "string",
      "value": "[reference('linkedTemplate').outputs.greetingMessage.value]"
    }
  }
}

下列範例所顯示的範本,會部署公用 IP 位址,並會針對該公用 IP,傳回 Azure 資源的資源識別碼:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "publicIPAddresses_name": {
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2021-02-01",
      "name": "[parameters('publicIPAddresses_name')]",
      "location": "eastus",
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Dynamic",
        "idleTimeoutInMinutes": 4
      },
      "dependsOn": []
    }
  ],
  "outputs": {
    "resourceID": {
      "type": "string",
      "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_name'))]"
    }
  }
}

若要在部署負載平衡器時使用上述範本中的公用 IP 位址,請連結到該範本並宣告其相依於 Microsoft.Resources/deployments 資源。 負載平衡器上的公用 IP 位址會設定為從連結的範本傳回的輸出值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "loadBalancers_name": {
      "defaultValue": "mylb",
      "type": "string"
    },
    "publicIPAddresses_name": {
      "defaultValue": "myip",
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/loadBalancers",
      "apiVersion": "2021-02-01",
      "name": "[parameters('loadBalancers_name')]",
      "location": "eastus",
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "LoadBalancerFrontEnd",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[reference('linkedTemplate').outputs.resourceID.value]"
              }
            }
          }
        ],
        "backendAddressPools": [],
        "loadBalancingRules": [],
        "probes": [],
        "inboundNatRules": [],
        "outboundNatRules": [],
        "inboundNatPools": []
      },
      "dependsOn": [
        "[resourceId('Microsoft.Resources/deployments', 'linkedTemplate')]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'public-ip.json')]",
          "contentVersion": "1.0.0.0"
        },
        "parameters": {
          "publicIPAddresses_name": { "value": "[parameters('publicIPAddresses_name')]" }
        }
      }
    }
  ]
}

部署歷程記錄

在部署歷程記錄中,Resource Manager 會以個別部署的方式處理每一個範本。 具有三個連結或巢狀範本的主要範本,在部署歷程記錄中會顯示為:

Deployment history

您可以使用歷程記錄中的這些個別項目,以在部署後擷取輸出值。 下列範本會建立公用 IP 位址,並輸出 IP 位址:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "publicIPAddresses_name": {
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2021-02-01",
      "name": "[parameters('publicIPAddresses_name')]",
      "location": "southcentralus",
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static",
        "idleTimeoutInMinutes": 4,
        "dnsSettings": {
          "domainNameLabel": "[concat(parameters('publicIPAddresses_name'), uniqueString(resourceGroup().id))]"
        }
      },
      "dependsOn": []
    }
  ],
  "outputs": {
    "returnedIPAddress": {
      "type": "string",
      "value": "[reference(parameters('publicIPAddresses_name')).ipAddress]"
    }
  }
}

下列範本會連結至先前的範本。 它會建立三個公用 IP 位址。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "[concat('linkedTemplate', copyIndex())]",
      "copy": {
        "count": 3,
        "name": "ip-loop"
      },
      "properties": {
        "mode": "Incremental",
        "templateLink": {
        "uri": "[uri(deployment().properties.templateLink.uri, 'static-public-ip.json')]",
        "contentVersion": "1.0.0.0"
        },
        "parameters":{
          "publicIPAddresses_name":{"value": "[concat('myip-', copyIndex())]"}
        }
      }
    }
  ]
}

在部署後,您可以使用下列 PowerShell 指令碼擷取輸出值:

$loopCount = 3
for ($i = 0; $i -lt $loopCount; $i++)
{
  $name = 'linkedTemplate' + $i;
  $deployment = Get-AzResourceGroupDeployment -ResourceGroupName examplegroup -Name $name
  Write-Output "deployment $($deployment.DeploymentName) returned $($deployment.Outputs.returnedIPAddress.value)"
}

或者,在 Bash 殼層中使用 Azure CLI 指令碼:

#!/bin/bash

for i in 0 1 2;
do
  name="linkedTemplate$i";
  deployment=$(az deployment group show -g examplegroup -n $name);
  ip=$(echo $deployment | jq .properties.outputs.returnedIPAddress.value);
  echo "deployment $name returned $ip";
done

保護外部範本

雖然連結的範本必須可從外部存取,但它不必供大眾存取。 您可以將您的範本新增至只有儲存體帳戶擁有者可以存取的私人儲存體帳戶。 接著,在部署期間建立共用存取簽章 (SAS) Token 來啟用存取權。 您會將該 SAS Token 加入連結範本的 URI。 即使該 Token 是以安全字串來傳遞,連結範本的 URI (包括 SAS Token) 還是會記錄在部署作業中。 為了限制公開的程度,請為該 Token 設定到期日。

當然,也可以將參數檔案限制為透過 SAS Token 存取。

您目前無法連結到位於 Azure 儲存體防火牆後的儲存體帳戶中之範本。

重要

請考慮建立範本規格,而不是使用 SAS 權杖保護連結範本。範本規格可將主要範本及其連結範本,安全地儲存為 Azure 訂閱中的資源。 您可以使用 Azure RBAC,為需要部署範本的使用者,授與存取權。

下列範例顯示如何在連結到範本時傳遞 SAS 權杖:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containerSasToken": { "type": "securestring" }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[concat(uri(deployment().properties.templateLink.uri, 'helloworld.json'), parameters('containerSasToken'))]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
  }
}

在 PowerShell 中,您會取得容器的 Token 並使用下列命令部署範本。 請注意,containerSasToken 參數會定義在範本中, 而不是 New-AzResourceGroupDeployment 命令中的參數。

Set-AzCurrentStorageAccount -ResourceGroupName ManageGroup -Name storagecontosotemplates
$token = New-AzStorageContainerSASToken -Name templates -Permission r -ExpiryTime (Get-Date).AddMinutes(30.0)
$url = (Get-AzStorageBlob -Container templates -Blob parent.json).ICloudBlob.uri.AbsoluteUri
New-AzResourceGroupDeployment -ResourceGroupName ExampleGroup -TemplateUri ($url + $token) -containerSasToken $token

如果在 Bash 殼層中使用 Azure CLI,您應取得容器的權杖,並使用下列指令碼部署範本:

#!/bin/bash

expiretime=$(date -u -d '30 minutes' +%Y-%m-%dT%H:%MZ)
connection=$(az storage account show-connection-string \
  --resource-group ManageGroup \
  --name storagecontosotemplates \
  --query connectionString)
token=$(az storage container generate-sas \
  --name templates \
  --expiry $expiretime \
  --permissions r \
  --output tsv \
  --connection-string $connection)
url=$(az storage blob url \
  --container-name templates \
  --name parent.json \
  --output tsv \
  --connection-string $connection)
parameter='{"containerSasToken":{"value":"?'$token'"}}'
az deployment group create --resource-group ExampleGroup --template-uri $url?$token --parameters $parameter

範本的範例

下列範例顯示連結範本的一般用途。

主要的範本 連結的範本 Description
Hello World 連結的範本 從連結的範本傳回字串。
使用公用 IP 位址的負載平衡器 連結的範本 從連結的範本傳回公用 IP 位址,並且在負載平衡器中設定該值。
多個 IP 位址 連結的範本 在連結的範本中建立數個公用 IP 位址。

後續步驟