Развертывание ресурсов 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": "2025-04-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          <nested-template-syntax>
        }
      }
    }
  ]
}

В следующем примере учетная запись для хранения развертывается с помощью вложенного шаблона.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "defaultValue": "[format('{0}{1}', 'store', uniqueString(resourceGroup().id))]"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2025-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": "2025-06-01",
              "name": "[parameters('storageAccountName')]",
              "location": "[parameters('location')]",
              "sku": {
                "name": "Standard_LRS"
              },
              "kind": "StorageV2"
            }
          ]
        }
      }
    }
  ]
}

Вложенные ресурсы нельзя использовать в шаблоне символьного имени. В следующем шаблоне ресурс вложенной учетной записи хранения не может использовать символьное имя:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "2.0",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "defaultValue": "[format('{0}{1}', 'storage', uniqueString(resourceGroup().id))]"

    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": {
    "mainStorage": {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2025-06-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2"
    },
    "nestedResource": {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2025-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": "2025-06-01",
              "name": "[format('{0}nested', parameters('storageAccountName'))]",
              "location": "[parameters('location')]",
              "sku": {
                "name": "Standard_LRS"
              },
              "kind": "StorageV2"
            }
          ]
        }
      }
    }
  }
}

Область видимости вычислений выражений во вложенных шаблонах

При использовании вложенного шаблона можно указать, вычисляются ли выражения шаблонов в пределах области родительского шаблона или вложенного шаблона. Область определяет, как разрешаются такие параметры, переменные и функции, как resourceGroup и subscription.

Вы задаёте область с помощью свойства expressionEvaluationOptions. По умолчанию свойство expressionEvaluationOptions имеет значение outer. Это означает, что используется область родительского шаблона. Задайте значение inner, чтобы выражения вычислялись в области вложенного шаблона.

Внимание

Для languageVersion 2.0 значение по умолчанию для свойства expressionEvaluationOptionsinner. Значение outer заблокировано.

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

Примечание.

Если задана область outer, вы не можете использовать функциюreference в разделе outputs вложенного шаблона для ресурса, который развернут во вложенном шаблоне. Чтобы вернуть значения развернутого ресурса в вложенном шаблоне, либо используйте область 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": "2025-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 изменяется в зависимости от значения свойства scope в expressionEvaluationOptions. В таблице ниже показаны результаты для обеих областей.

Область оценки Выходные данные
внутренний из вложенного шаблона
внешний (или по умолчанию) из родительского шаблона

В следующем примере выполняется развертывание SQL Server и получение секрета хранилища ключей, используемого для пароля. Область имеет значение inner, поскольку динамически создает идентификатор хранилища ключей (см. adminPassword.reference.keyVault во внешних шаблонах parameters) и передает его в качестве параметра вложенному шаблону.

{
  "$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": "2025-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": "[format('sql-{0}sql', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2022-05-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": {
  }
}

Будьте внимательны, используя значения защищенных параметров во вложенном шаблоне. Если область установлена на outer, то защищенные значения будут храниться в открытом виде в истории развертывания. Просматривая шаблон в журнале развертывания, пользователь может видеть защищенные значения. Вместо этого используйте область inner или добавьте к родительскому шаблону ресурсы, которым требуются защищенные значения.

В следующем фрагменте показано, какие значения являются или не защищены:

{
  "$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": "2025-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": "2025-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": "2025-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": "2025-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": "2025-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 укажите URI шаблона для включения. В следующем примере приведена ссылка на шаблон, который хранится в учетной записи хранения.

{
  "$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": "2025-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 должен иметь доступ к шаблону. Укажите значение URI, загружаемое как HTTP или HTTPS.

Вы можете ссылаться на шаблоны с помощью параметров, включающих HTTP или HTTPS. Например, распространенным способом является использование параметра _artifactsLocation. Связанный шаблон можно задать с помощью выражения, например:

"uri": "[format('{0}/shared/os-disk-parts-md.json{1}', parameters('_artifactsLocation'), parameters('_artifactsLocationSasToken'))]"

Если вы ссылаетесь на шаблон в GitHub, используйте сырой URL. Ссылка имеет формат: https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json. Чтобы получить необработанную ссылку, нажмите кнопку "Необработанный".

Screenshot выбора необработанного URL-адреса в GitHub.

Примечание.

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

Для связанных шаблонов можно вложить развертывание с несвязанным именем в шаблон символического имени, вложить развертывание с символическим именем в шаблон несвязанного имени или вложить развертывание с символическим именем в другой шаблон символического имени (или наоборот).

Параметры для связанного шаблона

Параметры для связанного шаблона можно указать во внешнем файле или встроить непосредственно. Если предоставляется внешний файл параметров, используйте свойство parametersLink:

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2025-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": "2025-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')]"
        }
      }
    }
  }
]

Нельзя использовать одновременно встроенные параметры и ссылку на их файл. Развертывание завершается с ошибкой, когда указываются parametersLink и parameters.

Используйте относительный путь для связанных шаблонов.

Свойство relativePath, являющееся частью Майкрософт.Resources/deployments, упрощает создание связанных шаблонов. Это свойство можно использовать для развертывания удаленного связанного шаблона в расположении, относящемся к родительскому элементу. Эта функция требует, чтобы все файлы шаблонов были подготовлены и доступны по удаленному URI, например, в GitHub или учетной записи хранения Azure. При вызове основного шаблона с помощью URI из Azure PowerShell или Azure CLI дочерний URI для развертывания является сочетанием родительского и относительного пути.

Примечание.

При создании templateSpec все шаблоны, на которые ссылается свойство relativePath, упаковываются в ресурс templateSpec с помощью Azure PowerShell или Azure CLI. Для этого не требуется размещение файлов. Дополнительные сведения см. в статье "Создание спецификации шаблона с связанными шаблонами".

Предположим, что структура папок выглядит следующим образом:

Диаграмма, показывающая структуру папок для относительного пути связанного шаблона Resource Manager.

В следующем шаблоне показано, как 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": "2025-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, чтобы указать маркер SAS, используемый с параметром TemplateUri. Этот параметр поддерживается только 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": "2025-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": "2025-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 для свойства templateLink или parametersLink. Если не указать contentVersion, развертывается текущая версия шаблона. Если предоставить значение для версии содержимого, оно должно совпадать с версией связанного шаблона, в противном случае развертывание завершится ошибкой.

В предыдущих примерах были показаны жестко запрограммированные значения URL-адреса для ссылок на шаблоны. Этот подход может действовать для простого шаблона, но неэффективен для большого набора модульных шаблонов. Вместо этого можно создать статическую переменную, которая содержит базовый URL-адрес для основного шаблона, а затем динамически создавать URL-адреса для связанных шаблонов на основе этого адреса. Преимущество этого подхода заключается в том, что его можно с легкостью перемещать или разветвлять, поскольку для этого надо лишь изменить статическую переменную в основном шаблоне. Основной шаблон передает правильные URI через весь разложенный шаблон.

В следующем примере показано, как использовать базовый URL-адрес для создания двух URL-адресов для связанных шаблонов sharedTemplateUrl и vmTemplateUrl:

"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-адреса непосредственно в файле шаблона. Свойство templateLink возвращается только при создании связи с удаленным шаблоном по URL-адресу. Если вы используете локальный шаблон, свойство недоступно.

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

В конечном итоге вы бы использовали переменную в свойстве uri свойства templateLink.

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

Использование копирования

Чтобы создать несколько экземпляров ресурса с вложенным шаблоном, добавьте элемент copy на уровне ресурса Майкрософт.Resources/deployments. Либо, если область имеет значение inner, можно добавить копию в рамках вложенного шаблона.

В следующем примере шаблона показано, как использовать copy с вложенным шаблоном.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2025-04-01",
    "name": "[format('nestedTemplate{0}', 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": "2025-06-01",
            "name": "[format('{0}{1}', 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": "2025-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-адрес и возвращает идентификатор Azure ресурса для этого 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": "2025-01-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-адрес из предыдущего шаблона при развертывании подсистемы балансировки нагрузки, свяжите с шаблоном и объявите зависимость от ресурса Майкрософт.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": "2025-01-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": "2025-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 обрабатывает каждый шаблон как отдельное развертывание в журнале развертывания. Основной шаблон с тремя связанными или вложенными шаблонами отображается в журнале развертывания следующим образом.

Скриншот истории развертывания на портале Azure.

С помощью этих отдельных записей в журнале можно извлечь выходные значения после развертывания. Следующий шаблон создает общедоступный IP-адрес и выводит IP-адрес:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "publicIPAddresses_name": {
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2025-01-01",
      "name": "[parameters('publicIPAddresses_name')]",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static",
        "idleTimeoutInMinutes": 4,
        "dnsSettings": {
          "domainNameLabel": "[format('{0}{1}', 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": "2025-04-01",
      "name": "[format('linkedTemplate{0}', 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": "[format('myip-{0}', 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)"
}

Или скрипт Azure CLI в оболочке Bash:

#!/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, чтобы обеспечить доступ во время развертывания. Вы добавляете этот токен SAS к URI связанного шаблона. Несмотря на то, что токен передается в защищенной строке, URI связанного шаблона, содержащий SAS токен, добавляется в журнал операций развертывания. Чтобы снизить риск раскрытия, задайте срок действия маркера.

Файл параметров также может быть ограничен доступом через маркер SAS.

В настоящее время вы не можете ссылаться на шаблон в учетной записи хранения, которая находится за брандмауэром служба хранилища Azure.

Внимание

Вместо защиты связанного шаблона с помощью маркера SAS рекомендуется создать спецификацию template. Спецификация шаблона безопасно сохраняет основной шаблон и связанные шаблоны в качестве ресурса в подписке 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": "2025-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[format('{0}{1}', uri(deployment().properties.templateLink.uri, 'helloworld.json'), parameters('containerSasToken'))]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
  }
}

В PowerShell сначала получите токен для контейнера, а затем разверните шаблоны с помощью следующих команд. Обратите внимание, что параметр 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

Для Azure CLI в оболочке Bash вы получите токен для контейнера, а также развернёте шаблоны с помощью следующего кода:

#!/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

Образцы шаблонов

В следующих примерах показаны наиболее частые способы использования связанных шаблонов.

Основной шаблон Связанный шаблон Описание
Всем привет связанный шаблон Возвращает строку из связанного шаблона.
Load Balancer с общедоступным IP-адресом связанный шаблон Возвращает общедоступный IP-адрес из связанного шаблона и задает это значение в подсистеме балансировки нагрузки.
Множественные IP-адреса связанный шаблон Создает несколько общедоступных IP-адресов в связанном шаблоне.

Следующие шаги