在 ARM 模板中定义部署资源的顺序

部署资源时,可能需要确保某些资源在其他资源之前存在。 例如,在部署数据库之前,需要逻辑 SQL Server。 可通过将一个资源标记为依赖于其他资源来建立此关系。 使用 dependsOn 元素可以定义显式依赖关系。 使用 reference 或 list 函数可以定义隐式依赖关系。

Azure 资源管理器将评估资源之间的依赖关系,并根据其依赖顺序进行部署。 如果资源互不依赖,资源管理器将以并行方式部署资源。 只需为部署在同一模板中的资源定义依赖关系。

提示

我们建议使用 Bicep,因为它提供与 ARM 模板相同的功能,并且该语法更易于使用。 若要了解详细信息,请参阅资源依赖项

dependsOn

在 Azure 资源管理器模板(ARM 模板)中,dependsOn 元素可让你将一个资源定义为依赖于一个或多个资源。 其值是字符串的 JavaScript 对象表示法 (JSON) 数组,每个字符串都是一个资源名称或 ID。 该数组可以包括有条件部署的资源。 条件资源未部署时,Azure 资源管理器会自动将其从所需依赖项中删除。

以下示例显示了一个依赖于虚拟网络、网络安全组和公共 IP 地址的网络接口。 有关完整的模板,请参阅适用于 Linux VM 的快速入门模板

{
  "type": "Microsoft.Network/networkInterfaces",
  "apiVersion": "2022-07-01",
  "name": "[variables('networkInterfaceName')]",
  "location": "[parameters('location')]",
  "dependsOn": [
    "[resourceId('Microsoft.Network/networkSecurityGroups/', parameters('networkSecurityGroupName'))]",
    "[resourceId('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]",
    "[resourceId('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]"
  ],
  ...
}

使用 languageVersion 2.0,在 dependsOn 数组中使用资源符号名称。 例如:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "2.0",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": {
    "myStorage": {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-01-01",
      "name": "[format('storage{0}', uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2"
    },
    "myVm": {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-03-01",
      "name": "[format('vm{0}', uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "myStorage"
      ],
      ...
    }
  }
}

尽管你可能倾向于使用 dependsOn 来映射资源之间的关系,但请务必了解这么做的理由。 例如,若要记录资源的互连方式,使用 dependsOn 并不是合适的方法。 部署后,资源不会在其属性中保留部署依赖项,因此没有可让你查看依赖项的命令或操作。 设置不必要的依赖关系会减慢部署速度,因为资源管理器无法并行部署这些资源。

子资源

子资源和父资源之间不会自动创建隐式部署依赖关系。 如果需要在父资源之后部署子资源,请设置 dependsOn 属性。

以下示例显示了逻辑 SQL Server 和数据库。 请注意,在数据库与服务器之间定义了显式依赖关系,尽管数据库是服务器的子级。

"resources": [
  {
    "type": "Microsoft.Sql/servers",
    "apiVersion": "2022-05-01-preview",
    "name": "[parameters('serverName')]",
    "location": "[parameters('location')]",
    "properties": {
      "administratorLogin": "[parameters('administratorLogin')]",
      "administratorLoginPassword": "[parameters('administratorLoginPassword')]"
    },
    "resources": [
      {
        "type": "databases",
        "apiVersion": "2022-05-01-preview",
        "name": "[parameters('sqlDBName')]",
        "location": "[parameters('location')]",
        "sku": {
          "name": "Standard",
          "tier": "Standard"
          },
        "dependsOn": [
          "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]"
        ]
      }
    ]
  }
]

有关完整的模板,请参阅适用于 Azure SQL 数据库的快速入门模板

reference 和 list 函数

引用函数使表达式能够从其他 JSON 名值对或运行时资源中派生其值。 list* 函数从列表操作返回资源的值。

reference 和 list 表达式隐式声明一个资源依赖于另一个资源。 只要可能,可使用隐式引用以避免添加不必要的依赖项。

若要强制实施隐式依赖关系,请按名称(而不是资源 ID)引用资源。 如果将资源 ID 传入到 reference 或 list 函数中,则不会创建隐式引用。

reference 函数的一般格式为:

reference('resourceName').propertyPath

listKeys 函数的一般格式为:

listKeys('resourceName', 'yyyy-mm-dd')

在以下示例中,CDN 终结点显式依赖于 CDN 配置文件,隐式依赖于 Web 应用。

{
    "type": "endpoints",
    "apiVersion": "2021-06-01",
    "name": "[variables('endpointName')]",
    "location": "[resourceGroup().location]",
    "dependsOn": [
      "[variables('profileName')]"
    ],
    "properties": {
      "originHostHeader": "[reference(variables('webAppName')).hostNames[0]]",
      ...
    }
    ...
}

若要了解详细信息,请参阅引用函数

依赖于循环中的资源

若要部署依赖于复制循环中资源的资源,可以使用两个选项。 你可以设置对循环中的个别资源的依赖关系,也可以设置对整个循环的依赖关系。

注意

在大多数情况下,应当设置对复制循环中的个别资源的依赖关系。 仅当循环中的所有资源都需要在创建下一个资源之前存在时,才依赖整个循环。 设置对整个循环的依赖关系会导致依赖关系图显著扩展,特别是当那些循环的资源依赖于其他资源时。 扩展的依赖关系使得部署很难有效完成。

以下示例展示了如何部署多个虚拟机。 该模板会创建相同数量的网络接口。 每个虚拟机都依赖于一个网络接口,而不是依赖于整个循环。

{
  "type": "Microsoft.Network/networkInterfaces",
  "apiVersion": "2022-07-01",
  "name": "[format('{0}-{1}', variables('nicPrefix'), copyIndex())]",
  "location": "[parameters('location')]",
  "copy": {
    "name": "nicCopy",
    "count": "[parameters('vmCount')]"
  },
  ...
},
{
  "type": "Microsoft.Compute/virtualMachines",
  "apiVersion": "2022-11-01",
  "name": "[format('{0}{1}', variables('vmPrefix'), copyIndex())]",
  "location": "[parameters('location')]",
  "dependsOn": [
    "[resourceId('Microsoft.Network/networkInterfaces',format('{0}-{1}', variables('nicPrefix'),copyIndex()))]"
  ],
  "copy": {
    "name": "vmCopy",
    "count": "[parameters('vmCount')]"
  },
  "properties": {
    "networkProfile": {
      "networkInterfaces": [
        {
          "id": "[resourceId('Microsoft.Network/networkInterfaces',format('(0)-(1)', variables('nicPrefix'), copyIndex()))]",
          "properties": {
            "primary": "true"
          }
        }
      ]
    },
    ...
  }
}

以下示例演示了如何在部署虚拟机之前部署三个存储帐户。 请注意,copy 元素的 name 设置为 storagecopy,而虚拟机的 dependsOn 元素也设置为 storagecopy

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}, copyIndex(), uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "copy": {
        "name": "storagecopy",
        "count": 3
      },
      "properties": {}
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2022-11-01",
      "name": "[format('VM{0}', uniqueString(resourceGroup().id))]",
      "dependsOn": ["storagecopy"],
      ...
    }
  ]
}

符号名称可用于 dependsOn 数组。 如果符号名称用于复制循环,则循环中的所有资源将添加为依赖项。 前面的示例可以编写为以下 JSON。 在示例中,myVM 取决于 myStorages 循环中的所有存储帐户。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "2.0",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": {
    "myStorages": {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}, copyIndex(), uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "copy": {
        "name": "storagecopy",
        "count": 3
      },
      "properties": {}
    },
    "myVM": {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2022-11-01",
      "name": "[format('VM{0}', uniqueString(resourceGroup().id))]",
      "dependsOn": ["myStorages"],
      ...
    }
  }
}

循环依赖项

Resource Manager 可在模板验证过程中确定循环依赖项。 如果收到有关循环依赖关系的错误,请评估你的模板,了解是否存在可以删除的依赖关系。 如果删除依赖关系不起作用,则可将一些部署操作移至子资源中来避免循环依赖关系。 请在具有循环依赖关系的资源之后部署子资源。 例如,假设要部署两个虚拟机,但必须在每个虚拟机上设置引用另一虚拟机的属性。 可以按下述顺序部署这两个虚拟机:

  1. vm1
  2. vm2
  3. vm1 上的扩展依赖于 vm1 和 vm2。 扩展在 vm1 上设置的值是从 vm2 获取的。
  4. vm2 上的扩展依赖于 vm1 和 vm2。 扩展在 vm2 上设置的值是从 vm1 获取的。

有关评估部署顺序和解决依赖项错误的信息,请参阅排查使用 Azure 资源管理器时的常见 Azure 部署错误

后续步骤