Usando modelos vinculados e aninhados ao implantar os recursos do Azure
Para implantar soluções complexas, você pode dividir seu modelo do ARM (Azure Resource Manager) em vários modelos relacionados e implantá-los juntos por meio de um modelo principal. Os modelos relacionados podem ser arquivos separados ou sintaxe de modelo que é inserida no modelo principal. Este artigo usa o termo modelo vinculado para se referir a um arquivo de modelo separado que é referenciado por meio de um link do modelo principal. Ele usa o termo modelo aninhado para referenciar sintaxe de modelo inserido no modelo principal.
Para pequenas e médias soluções, um único modelo é mais fácil de entender e manter. Você pode ver todos os recursos e valores em um único arquivo. Para cenários avançados, os modelos vinculados permitem que você detalhe a solução em componentes de destino. Você pode reutilizar esses modelos para outros cenários com facilidade.
Para um tutorial, confira Tutorial: Implantar um modelo vinculado.
Observação
Para modelos vinculados ou aninhados, você só pode definir o modo de implantação como Incremental. No entanto, o modelo principal pode ser implantado no modo completo. Se você implantar o modelo principal no modo completo e o modelo vinculado ou aninhado tiver como alvo o mesmo grupo de recursos, os recursos implantados no modelo vinculado ou aninhado serão incluídos na avaliação para a implantação do modo completo. A coleção combinada de recursos implantados no modelo principal e em modelos vinculados ou aninhados é comparada com os recursos existentes no grupo de recursos. Todos os recursos não incluídos nessa coleção combinada são excluídos.
Se o modelo vinculado ou aninhado tiver como alvo um grupo de recursos diferente, essa implantação usará o modo incremental. Para obter mais informações, confira Escopo da implantação.
Dica
Recomendamos o Bicep porque ele oferece as mesmas funcionalidades que os modelos do ARM e a sintaxe é mais fácil de usar. Para saber mais, confira módulos.
Modelo aninhado
Para aninhar um modelo, adicione um recurso de implantações ao seu modelo principal. Na propriedade template
, especifique a sintaxe do modelo.
{
"$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": "2022-09-01",
"name": "nestedTemplate1",
"properties": {
"mode": "Incremental",
"template": {
<nested-template-syntax>
}
}
}
]
}
O exemplo a seguir implanta uma conta de armazenamento por meio de um modelo aninhado.
{
"$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": "2022-09-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": "2022-09-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
}
]
}
}
}
]
}
Recursos aninhados não podem ser usados em um modelo de nome simbólico. No modelo a seguir, o recurso de conta de armazenamento aninhado não pode usar um nome simbólico:
{
"$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": "2022-09-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
},
"nestedResource": {
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-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": "2022-09-01",
"name": "[format('{0}nested', parameters('storageAccountName'))]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
}
]
}
}
}
}
}
Escopo de avaliação de expressão em modelos aninhados
Ao usar um modelo aninhado, você pode especificar se as expressões de modelo serão avaliadas dentro do escopo do modelo pai ou do próprio modelo aninhado. O escopo determina como os parâmetros, as variáveis e as funções, como resourceGroup e subscription são resolvidos.
Você define o escopo por meio da propriedade expressionEvaluationOptions
. Por padrão, a propriedade expressionEvaluationOptions
é definida como outer
, o que significa que ela usa o escopo do modelo pai. Defina o valor como inner
para fazer com que as expressões sejam avaliadas dentro do escopo do modelo aninhado.
Importante
Para languageVersion 2.0
, o valor padrão da propriedade expressionEvaluationOptions
é inner
. O valor outer
está bloqueado.
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-01",
"name": "nestedTemplate1",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
...
Observação
Quando o escopo é definido como outer
, não é possível usar a função reference
na seção de saídas de um modelo aninhado para um recurso que você implantou no modelo aninhado. Para retornar os valores de um recurso implantado em um modelo aninhado, use o escopo inner
ou converta seu modelo aninhado em um modelo vinculado.
O modelo a seguir demonstra como as expressões de modelo são resolvidas de acordo com o escopo. Ele contém uma variável chamada exampleVar
que é definida no modelo pai e no modelo aninhado. Ele retorna o valor da variável.
{
"$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": "2022-09-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]"
}
}
}
O valor de exampleVar
muda dependendo do valor da propriedade scope
em expressionEvaluationOptions
. A tabela a seguir mostra os resultados para ambos os escopos.
Escopo da avaliação | Saída |
---|---|
interna | do modelo aninhado |
externa (ou padrão) | do modelo pai |
O exemplo a seguir implanta um SQL Server e recupera um segredo do Key Vault a ser usado como senha. O escopo é definido como inner
porque cria dinamicamente a ID do cofre de chaves (confira adminPassword.reference.keyVault
nos modelos externos parameters
) e a transmite como um parâmetro para o modelo aninhado.
{
"$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": "2022-09-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": {
}
}
Tenha cuidado ao usar valores de parâmetros seguros em um modelo aninhado. Se você definir o escopo como externo, os valores seguros serão armazenados como texto sem formatação no histórico de implantação. Um usuário que exibe o modelo no histórico de implantação pode ver os valores seguros. Em vez disso, use o escopo interno ou adicione ao modelo pai os recursos que precisam de valores seguros.
O trecho a seguir mostra quais valores são seguros e quais não são seguros.
{
"$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": "2023-03-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": "2022-09-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": "2023-03-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": "2022-09-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": "2023-03-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
}
}
}
]
}
}
}
]
}
Modelo vinculado
Para vincular um modelo, adicione um recurso de implantações ao seu modelo principal. Na propriedade templateLink
, especifique o URI do modelo a ser incluído. O exemplo a seguir contém links para um modelo que está em uma conta de armazenamento.
{
"$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": "2022-09-01",
"name": "linkedTemplate",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
"contentVersion":"1.0.0.0"
}
}
}
],
"outputs": {
}
}
Ao fazer referência a um modelo vinculado, o valor de uri
não pode ser um arquivo local ou um arquivo que só está disponível em sua rede local. O Azure Resource Manager precisa ser capaz de acessar o modelo. Forneça um valor de URI que pode ser baixado como HTTP ou HTTPS.
Você pode referenciar modelos usando parâmetros que incluem HTTP ou HTTPS. Por exemplo, um padrão comum é usar o parâmetro _artifactsLocation
. Você pode definir o modelo vinculado com uma expressão como:
"uri": "[format('{0}/shared/os-disk-parts-md.json{1}', parameters('_artifactsLocation'), parameters('_artifactsLocationSasToken'))]"
Se você estiver vinculando a um modelo no GitHub, use a URL bruta. O link tem o formato: https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json
. Para obter o link bruto, selecione Raw.
Observação
Para implantar um modelo ou fazer referência a um modelo vinculado armazenado em um repositório do GitHub privado, consulte uma solução personalizada documentada em Criar uma oferta personalizada e segura portal do Azure. Você pode criar uma função do Azure que efetue pull do token do GitHub do Azure Key Vault.
Para modelos vinculados, você pode aninhar uma implantação de nome não simbólico dentro de um modelo de nome simbólico, ou aninhar uma implantação de nome simbólico dentro de um modelo não simbólico, ou aninhar uma implantação de nome simbólico dentro de outro modelo de nome simbólico, ou vice-versa.
Parâmetros para o modelo vinculado
Você pode fornecer os parâmetros para o modelo vinculado em um arquivo externo ou embutido. Ao fornecer um arquivo de parâmetro externo, use a propriedade parametersLink
:
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-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"
}
}
}
]
Para transmitir valores de parâmetro embutidos, use a propriedade parameters
.
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-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')]"
}
}
}
}
]
Você não pode usar os dois parâmetros inline e um link para um arquivo de parâmetros. A implementação falha com um erro quando parametersLink
e parameters
são especificados.
Usar caminho relativo para modelos vinculados
A propriedade relativePath
de Microsoft.Resources/deployments
facilita a criação de modelos vinculados. Essa propriedade pode ser usada para implantar um modelo vinculado remoto em um local relacionado com o pai. Esse recurso requer que todos os arquivos de modelo sejam preparados e estejam disponíveis em um URI remoto, como o GitHub ou a conta de armazenamento do Azure. Quando o modelo principal é chamado usando um URI do Azure PowerShell ou da CLI do Azure, o URI de implantação filho é uma combinação de pai e relativePath.
Observação
Ao criar um templateSpec, todos os modelos referenciados pela propriedade relativePath
são empacotados no recurso templateSpec pelo Azure PowerShell ou pela CLI do Azure. Isso não exige que os arquivos sejam preparados. Para obter mais informações, confira Criar uma especificação de modelo com modelos vinculados.
Suponha uma estrutura de pastas como esta:
O modelo a seguir mostra como mainTemplate.jsno implanta nestedChild.json ilustrado na imagem anterior.
{
"$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": "2022-09-01",
"name": "childLinked",
"properties": {
"mode": "Incremental",
"templateLink": {
"relativePath": "children/nestedChild.json"
}
}
}
],
"outputs": {}
}
Na implantação a seguir, o URI do modelo vinculado no modelo anterior é 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"
Para implantar modelos vinculados com caminho relativo armazenado em uma conta de armazenamento do Azure, use o parâmetro QueryString
/query-string
para especificar o token SAS a ser usado com o parâmetro TemplateUri. Só há suporte a esse parâmetro na CLI do Azure versão 2.18 ou posterior e no Azure PowerShell versão 5.4 ou posterior.
New-AzResourceGroupDeployment `
-Name linkedTemplateWithRelativePath `
-ResourceGroupName "myResourceGroup" `
-TemplateUri "https://stage20210126.blob.core.windows.net/template-staging/mainTemplate.json" `
-QueryString $sasToken
Verifique se não há "?" à esquerda no QueryString. A implantação adiciona um símbolo desses ao montar o URI para as implantações.
Especificações de modelo
Em vez de manter seus modelos vinculados em um ponto de extremidade acessível, é possível criar uma especificação de modelo que empacota o modelo principal e seus modelos vinculados em uma única entidade que você pode implantar. A especificação do modelo é um recurso na sua assinatura do Azure. Ela facilita o compartilhamento seguro do modelo com os usuários na organização. Você usa o controle de acesso baseado em função do Azure (Azure RBAC) para conceder acesso à especificação de modelo.
Para saber mais, veja:
- Tutorial: Criar uma especificação de modelo com modelos vinculados.
- Tutorial: Implantar uma especificação de modelo como um modelo vinculado.
Dependências
Assim como outros tipos de recurso, você pode definir dependências entre os modelos aninhados/vinculados. Se os recursos em um modelo aninhado/vinculado precisarem ser implantados antes dos recursos em um segundo modelo aninhado/vinculado, defina o segundo modelo como dependente do primeiro.
{
"$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
Você não precisa fornecer a propriedade contentVersion
para a propriedade templateLink
ou parametersLink
. Se você não fornecer uma contentVersion
, a versão atual do modelo será implantada. Se você fornecer um valor para a versão do conteúdo, ele deve corresponder à versão do modelo vinculado; caso contrário, a implantação falhará com um erro.
Usando variáveis para vincular modelos
Os exemplos anteriores mostraram valores codificados de URL para os vínculos de modelo. Essa abordagem pode funcionar para um modelo simples, mas não funciona bem com um grande conjunto de modelos modulares. Em vez disso, você pode criar uma variável estática que armazena uma URL de base para o modelo principal e, em seguida, criar dinamicamente URLs para os modelos vinculados dessa URL de base. A vantagem dessa abordagem é que você pode mover ou bifurcar o modelo, pois precisa alterar apenas a variável estática no modelo principal. O modelo principal passa os URIs corretos em todo o modelo decomposto.
O exemplo a seguir mostra como usar uma URL de base para criar duas URLs para modelos vinculados (sharedTemplateUrl
e 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')]"
}
Você também pode usar deployment() para obter a URL base para o modelo atual e usá-lo para obter a URL para outros modelos no mesmo local. Essa abordagem será útil se o local do modelo é alterado ou para evitar embutir URLs no arquivo de modelo. A propriedade templateLink
só será retornada na vinculação a um modelo remoto com uma URL. Se você estiver usando um modelo local, essa propriedade não estará disponível.
"variables": {
"sharedTemplateUrl": "[uri(deployment().properties.templateLink.uri, 'shared-resources.json')]"
}
Por fim, você usaria a variável na propriedade uri
de uma propriedade templateLink
.
"templateLink": {
"uri": "[variables('sharedTemplateUrl')]",
"contentVersion":"1.0.0.0"
}
Usando cópia
Para criar várias instâncias de um recurso com um modelo aninhado, adicione o elemento copy
no nível do recurso Microsoft.Resources/deployments
. Ou, se o escopo for inner
, você poderá adicionar a cópia dentro do modelo aninhado.
O exemplo de modelo a seguir mostra como usar copy
com um modelo aninhado.
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-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": "2022-09-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
// }
}
]
}
}
}
]
Obter valores de modelos vinculados
Para obter um valor de saída de um modelo vinculado, recupere o valor da propriedade com uma sintaxe semelhante a: "[reference('deploymentName').outputs.propertyName.value]"
.
Ao obter uma propriedade de saída de um modelo vinculado, o nome da propriedade não pode incluir um traço.
Os exemplos a seguir demonstram como fazer referência a um modelo vinculado e recuperar um valor de saída. O modelo vinculado retorna uma mensagem simples. Primeiro, o modelo vinculado:
{
"$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"
}
}
}
O modelo principal implanta o modelo vinculado e obtém o valor retornado. Observe que ele faz referência aos recursos de implantação por nome, e ele usa o nome da propriedade retornada pelo modelo vinculado.
{
"$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]"
}
}
}
O exemplo a seguir mostra um modelo que implanta um endereço IP público e retorna a ID de recurso do recurso do Azure para esse IP público:
{
"$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'))]"
}
}
}
Para usar o endereço IP público do modelo anterior ao implantar um balanceador de carga, vincule ao modelo e declare uma dependência no recurso Microsoft.Resources/deployments
. O endereço IP público no balanceador de carga é definido como o valor de saída do modelo vinculado.
{
"$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')]" }
}
}
}
]
}
Histórico de implantações
O Gerenciador de Recursos trata cada modelo como uma implantação separada no histórico de implantações. Um modelo principal com três modelos vinculados ou aninhados aparece no histórico de implantação como:
Você pode usar essas entradas separadas no histórico para recuperar valores de saída após a implantação. O modelo a seguir cria um endereço IP público e gera o endereço 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": "2023-04-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]"
}
}
}
Os seguintes links de modelo para o modelo anterior. Ele cria três endereços IP públicos.
{
"$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": "2022-09-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())]"}
}
}
}
]
}
Após a implantação, você pode recuperar os valores de saída com o seguinte script do 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)"
}
Ou, script da CLI do Azure em um shell 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
Proteger um modelo externo
Embora o modelo vinculado precise estar disponível externamente, ele não precisa estar disponível para o público. Você pode adicionar o modelo a uma conta de armazenamento privada que pode ser acessada somente pelo proprietário da conta de armazenamento. Em seguida, você cria um token SAS (assinatura de acesso compartilhado) para permitir o acesso durante a implantação. Você pode adicionar esse token SAS ao URI para o modelo vinculado. Embora o token seja transmitido como uma cadeia de caracteres segura, o URI do modelo vinculado, incluindo o token SAS, é registrado nas operações de implantação. Para limitar a exposição, defina uma expiração para o token.
O arquivo de parâmetro também pode ter o acesso limitado por meio de um token SAS.
No momento, não é possível vincular a um modelo em uma conta de armazenamento que esteja atrás de um firewall do Armazenamento do Microsoft Azure.
Importante
Em vez de proteger seu modelo vinculado com um token SAS, considere a criação de uma especificação de modelo. A especificação de modelo armazena com segurança o modelo principal e seus modelos vinculados como um recurso em sua assinatura do Azure. Você usa o Azure RBAC para conceder acesso a usuários que precisam implantar o modelo.
O exemplo a seguir mostra como passar um token SAS ao vincular a um modelo:
{
"$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": "2022-09-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": {
}
}
No PowerShell, você obtém um token para o contêiner e implanta os modelos com os comandos a seguir. Observe que o parâmetro containerSasToken
está definido no modelo. Ele não é um parâmetro no comando 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
Para a CLI do Azure em um shell Bash, você obtém um token para o contêiner e implanta os modelos com o seguinte código:
#!/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
Modelos de exemplo
Os exemplos a seguir mostram os usos comuns dos modelos vinculados.
Modelo principal | Modelo vinculado | Descrição |
---|---|---|
Olá, Mundo | o modelo vinculado | Retorna a cadeia de caracteres do modelo vinculado. |
Azure Load Balancer com o endereço IP público | o modelo vinculado | Retorna o endereço IP público do modelo vinculado e define esse valor no balanceador de carga. |
Vários endereços IP | o modelo vinculado | Cria vários endereços IP públicos no modelo vinculado. |
Próximas etapas
- Para percorrer um tutorial, confira Tutorial: Implantar um modelo vinculado.
- Para saber mais sobre como definir a ordem de implantação para seus recursos, confira Definir a ordem de implantação de recursos em modelos do ARM.
- Para aprender a definir um recurso, mas criar várias instâncias dele, confira Iteração de recursos em modelos do ARM.
- Para ver as etapas para configurar um modelo em uma conta de armazenamento e gerar um token SAS, confira Implantar recursos com modelos do ARM e o Azure PowerShell ou Implantar recursos com modelos do ARM e a CLI do Azure.