Определение порядка развертывания ресурсов в шаблонах ARM

При развертывании ресурсов бывает так, что некоторые ресурсы должны существовать до начала создания других ресурсов. Например, для развертывания базы данных требуется логический сервер SQL. Такую связь вы можете определить, обозначив один ресурс как зависимый от другого. Используйте элемент dependsOn, чтобы определить явную зависимость. Используйте функции reference или list, чтобы определить неявную зависимость.

Azure Resource Manager оценивает зависимости между ресурсами и развертывает эти ресурсы согласно установленным зависимостям. Если ресурсы не зависят друг от друга, диспетчер ресурсов развертывает их параллельно. Необходимо только определить зависимости для ресурсов, которые развертываются в том же шаблоне.

Совет

Мы рекомендуем использовать Bicep, так как он предоставляет те же возможности, что и шаблоны ARM, и имеет более простой синтаксис. Дополнительные сведения см. в описании зависимостей ресурсов.

Свойство dependsOn

В шаблоне Azure Resource Manager (шаблон ARM) элемент dependsOn позволяет определить один ресурс как зависимый от одного или нескольких других ресурсов. Его значение является массивом строк в формате JSON (нотация объектов JavaScript), где каждый объект является именем или идентификатором ресурса. Массив может содержать ресурсы с условным развертыванием. Если условный ресурс не развернут, Azure Resource Manager автоматически удаляет его из числа необходимых зависимостей.

В следующем примере показан сетевой интерфейс, который зависит от виртуальной сети, группы безопасности сети и общедоступного IP-адреса. Полный шаблон см. в шаблоне быстрого запуска для виртуальной машины Linux.

{
  "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 и базу данных SQL. Как вы видите, между базой данных SQL и сервером SQL пришлось определить явную зависимость, хотя эта база данных является дочерним ресурсом по отношению к серверу.

"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'))]"
        ]
      }
    ]
  }
]

Полный шаблон можно найти здесь.

Функции list и reference

Функция reference позволяет выражению получать его значение из других пар "имя JSON — значение" или ресурсов среды выполнения. Функции list* возвращают значение ресурса из списка операций.

Выражения reference и list неявно объявляют, что один ресурс зависит от другого. По возможности используйте неявные ссылки, чтобы избежать добавления ненужных зависимостей.

Чтобы применить неявную зависимость, указывайте имя ресурса, а не идентификатор. При передаче идентификатора ресурса функциям list или reference неявные ссылки созданы не будут.

Общий формат функции reference выглядит следующим образом:

reference('resourceName').propertyPath

Общий формат функции listKeys выглядит следующим образом:

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

В следующем примере конечная точка CDN явно зависит от профиля CDN и неявно зависит от веб-приложения.

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

Дополнительные сведения см. в разделе о функции reference.

Зависимость от ресурсов в цикле

У вас есть два варианта развертывания ресурсов, зависящих от других ресурсов в цикле копирования. Можно задать зависимость от каждого ресурса в цикле или от всего цикла сразу.

Примечание

В большинстве случаев лучше указывать зависимость от отдельных ресурсов в цикле копирования. Зависимость от всего цикла следует использовать только в том случае, если все ресурсы в этом цикле должны существовать до создания следующего ресурса. Установка зависимости от всего цикла приводит к значительному расширению схемы зависимостей, особенно если ресурсы в цикле также зависят от других ресурсов. Широкая схема зависимостей затрудняет эффективное выполнение развертывания.

Следующий пример демонстрирует развертывание нескольких виртуальных машин. Этот шаблон создает такое же количество сетевых интерфейсов. Каждая виртуальная машина зависит от одного сетевого интерфейса, но не от всего цикла.

{
  "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 Resource Manager.

Дальнейшие действия