跨范围部署 Azure 资源Deploy Azure resources across scopes

使用 Azure 资源管理器模板(ARM 模板),可以在单次部署中部署到多个范围。With Azure Resource Manager templates (ARM templates), you can deploy to more than one scope in a single deployment. 可用的范围是租户、管理组、订阅和资源组。The available scopes are a tenant, management groups, subscriptions, and resource groups. 例如,可以将资源部署到一个资源组,并在同一模板中将资源部署到另一个资源组。For example, you can deploy resources to one resource group, and in the same template deploy resources to another resource group. 或者,可以将资源部署到管理组,并且也将资源部署到该管理组中的资源组。Or, you can deploy resources to a management group and also deploy resources to a resource group within that management group.

请使用嵌套或链接模板来指定与部署操作的主范围不同的范围。You use nested or linked templates to specify scopes that are different than the primary scope for the deployment operation.

可用的范围Available scopes

用于部署操作的范围决定其他哪些范围可用。The scope that you use for the deployment operation determines which other scopes are available. 你可以部署到租户管理组订阅资源组You can deploy to the tenant, management group, subscription, or resource group. 从主部署级别中,不能在层次结构中向上提升级别。From the primary deployment level, you can't go up levels in the hierarchy. 例如,如果部署到订阅,则不能向上提升级别以将资源部署到管理组。For example, if you deploy to a subscription, you can't step up a level to deploy resources to a management group. 但是,可以部署到管理组并向下降低级别以部署到订阅或资源组。However, you can deploy to the management group and step down levels to deploy to a subscription or resource group.

对于每一个范围,部署模板的用户必须具有创建资源所必需的权限。For every scope, the user deploying the template must have the required permissions to create resources.

跨资源组Cross resource groups

若要将与父模板不同的资源组作为目标,请使用嵌套或链接模板To target a resource group that is different than the one for parent template, use a nested or linked template. 在部署资源类型中,为要将嵌套模板部署到的订阅 ID 和资源组指定值。Within the deployment resource type, specify values for the subscription ID and resource group that you want the nested template to deploy to. 资源组可以存在于不同的订阅中。The resource groups can exist in different subscriptions.

{
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2019-10-01",
  "name": "nestedTemplate",
  "resourceGroup": "[parameters('secondResourceGroup')]",
  "subscriptionId": "[parameters('secondSubscriptionID')]",

如果未指定订阅 ID 或资源组,将使用父模板中的订阅和资源组。If you don't specify the subscription ID or resource group, the subscription and resource group from the parent template are used. 在运行部署之前,所有资源组都必须存在。All the resource groups must exist before running the deployment.

备注

在单个部署中可以部署到 800 个资源组。You can deploy to 800 resource groups in a single deployment. 通常情况下,此限制意味着,在嵌套或链接的部署中可以部署到为父模板指定的一个资源组和最多 799 个资源组。Typically, this limitation means you can deploy to one resource group specified for the parent template, and up to 799 resource groups in nested or linked deployments. 但是,如果父模板仅包含嵌套或链接的模板,并且本身不部署任何资源,则在嵌套或链接的部署中最多可包含 800 个资源组。However, if your parent template contains only nested or linked templates and does not itself deploy any resources, then you can include up to 800 resource groups in nested or linked deployments.

以下示例部署两个存储帐户。The following example deploys two storage accounts. 第一个存储帐户部署到在部署操作中指定的资源组。The first storage account is deployed to the resource group specified in the deployment operation. 第二个存储帐户部署到在 secondResourceGroupsecondSubscriptionID 参数中指定的资源组:The second storage account is deployed to the resource group specified in the secondResourceGroup and secondSubscriptionID parameters:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storagePrefix": {
      "type": "string",
      "maxLength": 11
    },
    "secondResourceGroup": {
      "type": "string"
    },
    "secondSubscriptionID": {
      "type": "string",
      "defaultValue": ""
    },
    "secondStorageLocation": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "variables": {
    "firstStorageName": "[concat(parameters('storagePrefix'), uniqueString(resourceGroup().id))]",
    "secondStorageName": "[concat(parameters('storagePrefix'), uniqueString(parameters('secondSubscriptionID'), parameters('secondResourceGroup')))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-06-01",
      "name": "[variables('firstStorageName')]",
      "location": "[resourceGroup().location]",
      "sku":{
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2019-10-01",
      "name": "nestedTemplate",
      "resourceGroup": "[parameters('secondResourceGroup')]",
      "subscriptionId": "[parameters('secondSubscriptionID')]",
      "properties": {
      "mode": "Incremental",
      "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {},
          "variables": {},
          "resources": [
          {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2019-06-01",
            "name": "[variables('secondStorageName')]",
            "location": "[parameters('secondStorageLocation')]",
            "sku":{
              "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {
            }
          }
          ]
      },
      "parameters": {}
      }
    }
  ]
}

如果将 resourceGroup 设置为不存在的资源组的名称,则部署会失败。If you set resourceGroup to the name of a resource group that doesn't exist, the deployment fails.

若要测试上述模板并查看结果,请使用 PowerShell 或 Azure CLI。To test the preceding template and see the results, use PowerShell or Azure CLI.

备注

当我们使用以 https://raw.githubusercontent.com/ 开头的指定模板文件 URI 部署资源时,控制台有时将返回错误,如 Unable to download deployment contentWhen we deploy resource with specified template file URI that starts with https://raw.githubusercontent.com/, the console will be return error like Unable to download deployment content sometime.

可以执行以下操作来解决相应问题。We can follow the below actions to resolve corresponding issue.

  1. 下载指定 URI 的模板文件内容并以同一名称另存在本地电脑上。Download the template file content of specified URI and save as the same name on your local PC.

  2. TemplateUri 的参数替换为 TemplateFile,然后用下载的实际文件名更新指定的 URI,并再次运行。Replace the parameter of TemplateUri with TemplateFile, then update the specified URI with the download actual file name and run again.

    类别Category 参考链接Reference link 操作Action
    PowerShellPowerShell New-AzResourceGroupDeploymentNew-AzResourceGroupDeployment -TemplateUri 替换为 '-TemplateFile`Replace -TemplateUri with '-TemplateFile`
    Azure CLIAzure CLI az 部署组创建az deployment group create --template-uri 替换为 '--template-file`Replace --template-uri with '--template-file`

若要将两个存储帐户部署到同一订阅中的两个资源组,请使用:To deploy two storage accounts to two resource groups in the same subscription, use:

$firstRG = "primarygroup"
$secondRG = "secondarygroup"

New-AzResourceGroup -Name $firstRG -Location chinaeast
New-AzResourceGroup -Name $secondRG -Location chinaeast

New-AzResourceGroupDeployment `
  -ResourceGroupName $firstRG `
  -TemplateUri https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/crosssubscription.json `
  -storagePrefix storage `
  -secondResourceGroup $secondRG `
  -secondStorageLocation chinaeast

若要将两个存储帐户部署到两个订阅,请使用:To deploy two storage accounts to two subscriptions, use:

$firstRG = "primarygroup"
$secondRG = "secondarygroup"

$firstSub = "<first-subscription-id>"
$secondSub = "<second-subscription-id>"

Select-AzSubscription -Subscription $secondSub
New-AzResourceGroup -Name $secondRG -Location chinaeast

Select-AzSubscription -Subscription $firstSub
New-AzResourceGroup -Name $firstRG -Location chinaeast

New-AzResourceGroupDeployment `
  -ResourceGroupName $firstRG `
  -TemplateUri https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/crosssubscription.json `
  -storagePrefix storage `
  -secondResourceGroup $secondRG `
  -secondStorageLocation chinaeast `
  -secondSubscriptionID $secondSub

跨订阅、管理组和租户Cross subscription, management group, and tenant

为订阅、管理组和租户级别的部署指定不同范围时,可像资源组的示例那样使用嵌套部署。When specifying different scopes for subscription, management group and tenant level deployments, you use nested deployments like the example for resource groups. 用来指定范围的属性可能会有所不同。The properties that you use for specifying scope can differ. 有关部署级别的文章中介绍了这些方案。Those scenarios are covered in the articles about the levels of deployments. 有关详情,请参阅:For more information, see:

函数在范围中解析的方式How functions resolve in scopes

当部署到多个范围时,根据指定模板的方式不同,resourceGroup()subscription() 函数解析的方式也有所不同。When you deploy to more than one scope, the resourceGroup() and subscription() functions resolve differently based on how you specify the template. 链接到外部模板时,函数始终解析为该模板的作用域。When you link to an external template, the functions always resolve to the scope for that template. 在父模板中嵌套模板时,请使用 expressionEvaluationOptions 属性指定函数是否解析为父模板或嵌套模板的资源组和订阅。When you nest a template within a parent template, use the expressionEvaluationOptions property to specify whether the functions resolve to the resource group and subscription for the parent template or the nested template. 将属性设置为 inner,以便解析为嵌套模板的范围。Set the property to inner to resolve to the scope for the nested template. 将属性设置为 outer,以便解析为父模板的范围。Set the property to outer to resolve to the scope of the parent template.

下表显示了函数是解析为父资源组,还是解析为嵌入资源组和订阅。The following table shows whether the functions resolve to the parent or embedded resource group and subscription.

模板类型Template type 范围Scope 解决方法Resolution
嵌套nested 外部(默认值)outer (default) 父资源组Parent resource group
嵌套nested 内部inner 子资源组Sub resource group
链接linked 空值N/A 子资源组Sub resource group

以下示例模板演示:The following example template shows:

  • 具有默认(外部)范围的嵌套模板nested template with default (outer) scope
  • 具有内部范围的嵌套模板nested template with inner scope
  • 链接的模板linked 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",
            "name": "defaultScopeTemplate",
            "apiVersion": "2017-05-10",
            "resourceGroup": "inlineGroup",
            "properties": {
                "mode": "Incremental",
                "template": {
                    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "parameters": {},
                    "variables": {},
                    "resources": [
                    ],
                    "outputs": {
                        "resourceGroupOutput": {
                            "type": "string",
                            "value": "[resourceGroup().name]"
                        }
                    }
                },
                "parameters": {}
            }
        },
        {
            "type": "Microsoft.Resources/deployments",
            "name": "innerScopeTemplate",
            "apiVersion": "2017-05-10",
            "resourceGroup": "inlineGroup",
            "properties": {
                "expressionEvaluationOptions": {
                    "scope": "inner"
                },
                "mode": "Incremental",
                "template": {
                    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "parameters": {},
                    "variables": {},
                    "resources": [
                    ],
                    "outputs": {
                        "resourceGroupOutput": {
                            "type": "string",
                            "value": "[resourceGroup().name]"
                        }
                    }
                },
                "parameters": {}
            }
        },
        {
            "apiVersion": "2017-05-10",
            "name": "linkedTemplate",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "linkedGroup",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "contentVersion": "1.0.0.0",
                    "uri": "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/resourceGroupName.json"
                },
                "parameters": {}
            }
        }
    ],
    "outputs": {
        "parentRG": {
            "type": "string",
            "value": "[concat('Parent resource group is ', resourceGroup().name)]"
        },
        "defaultScopeRG": {
            "type": "string",
            "value": "[concat('Default scope resource group is ', reference('defaultScopeTemplate').outputs.resourceGroupOutput.value)]"
        },
        "innerScopeRG": {
            "type": "string",
            "value": "[concat('Inner scope resource group is ', reference('innerScopeTemplate').outputs.resourceGroupOutput.value)]"
        },
        "linkedRG": {
            "type": "string",
            "value": "[concat('Linked resource group is ', reference('linkedTemplate').outputs.resourceGroupOutput.value)]"
        }
    }
}

若要测试上述模板并查看结果,请使用 PowerShell 或 Azure CLI。To test the preceding template and see the results, use PowerShell or Azure CLI.

New-AzResourceGroup -Name parentGroup -Location chinaeast
New-AzResourceGroup -Name inlineGroup -Location chinaeast
New-AzResourceGroup -Name linkedGroup -Location chinaeast

New-AzResourceGroupDeployment `
  -ResourceGroupName parentGroup `
  -TemplateUri https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/crossresourcegroupproperties.json

前述示例的输出为:The output from the preceding example is:

 Name             Type                       Value
 ===============  =========================  ==========
 parentRG         String                     Parent resource group is parentGroup
 defaultScopeRG   String                     Default scope resource group is parentGroup
 innerScopeRG     String                     Inner scope resource group is inlineGroup
 linkedRG         String                     Linked resource group is linkedgroup

后续步骤Next steps