Definir a ordem de implantação de recursos em modelos do ARM

Ao implantar recursos, talvez seja necessário verificar se existem alguns recursos antes de outros. Por exemplo, é preciso obter um SQL Server lógico antes de implantar um banco de dados. Estabeleça essa relação tornando um recurso dependente de outro recurso. Use o elemento dependsOn para definir uma dependência explícita. Use as funções de referência ou lista para definir uma dependência implícita.

O Azure Resource Manager avalia as dependências entre os recursos, depois executa a implantação deles por ordem de dependência. Quando os recursos não dependem uns dos outros, o Gerenciador de Recursos os implanta paralelamente. Você só precisa definir as dependências para recursos que são implantados no mesmo modelo.

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 dependências de recurso.

dependsOn

No modelo do ARM (modelo do Azure Resource Manager), o elemento dependsOn permite definir um recurso como dependente de um ou mais recursos. O valor dele é a matriz de cadeias de caracteres JSON (JavaScript Object Notation). Além disso, cada uma delas representa um nome ou uma ID do recurso. A matriz pode incluir recursos implantados de modo condicional. Quando um recurso condicional não é implantado, o Azure Resource Manager o remove automaticamente das dependências necessárias.

O exemplo a seguir mostrará um adaptador de rede que depende de itens como rede virtual, endereço IP público e grupo de segurança de rede. Para obter um modelo completo, confira o Modelo de início rápido para uma VM do 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'))]"
  ],
  ...
}

Com languageVersion 2.0, use o nome simbólico do recurso em dependsOn matrizes. Por exemplo:

{
  "$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"
      ],
      ...
    }
  }
}

Embora tenha interesse em usar dependsOn para mapear as relações entre os recursos, recomendamos entender por que você deseja executar esse tipo de ação. Por exemplo, para documentar de que modo os recursos estão interconectados, usar dependsOn não é técnica mais adequada. Após a implantação, o recurso não reterá as dependências de implantação em suas propriedades, portanto, não haverá comandos ou operações que permitirão ver as dependências. Configurar dependências desnecessárias reduz o tempo de implantação porque o Resource Manager não poderá implantar esses recursos em paralelo.

Recursos filho

A dependência de uma implantação implícita não é criada de modo automático entre um recurso filho e um recurso pai. Caso precise implantar o recurso filho após o recurso pai, defina a propriedade dependsOn.

O exemplo a seguir mostrará um SQL Server lógico e um banco de dados. Observe que uma dependência explícita será definida entre o banco de dados e o servidor, embora o banco de dados seja um elemento filho do servidor.

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

Para conferir um modelo completo, confira o Modelo de início rápido para o Banco de Dados SQL do Azure.

funções de referência e lista

A função de referência permite que uma expressão derive seu valor de outro nome JSON e de pares de valor ou de recursos de runtime. O lista * funções retornar valores para um recurso de uma operação de lista.

Expressões de referência e lista declaram de modo implícito que um recurso depende de outro. Sempre que possível, use uma referência implícita para evitar adicionar uma dependência desnecessária.

Para impor uma dependência implícita, confira o recurso por nome, não por ID do recurso. Se você passar a ID de recurso para as funções de referência ou lista, não será criada uma referência implícita.

O formato geral da função reference é:

reference('resourceName').propertyPath

O formato geral da função listKeys é:

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

No exemplo a seguir, um ponto de extremidade CDN depende explicitamente do perfil CDN e implicitamente de um aplicativo Web.

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

Para saber mais, consulte Função de referência.

Depender dos recursos em um loop

Há duas opções para implantar recursos que dependem de recursos em um loop de cópia. É possível definir uma dependência em recursos individuais no loop ou em um loop inteiro.

Observação

Na maioria dos cenários, será preciso definir a dependência em recursos individuais dentro do loop de cópia. Somente dependa de um loop inteiro quando precisar que todos os recursos existam no loop antes de criar o próximo recurso. Configurar a dependência no loop inteiro fará com que o grafo de dependências se expanda de modo significativo, principalmente se esses recursos com loop dependem de outros recursos. As dependências expandidas dificultam a conclusão da implantação de modo eficiente.

O exemplo a seguir mostrará de que modo implantar várias máquinas virtuais. O modelo criará o mesmo número de interfaces de rede. Cada máquina virtual depende de um adaptador de rede, em vez de um loop inteiro.

{
  "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"
          }
        }
      ]
    },
    ...
  }
}

O exemplo a seguir mostrará de que modo implantar três contas de armazenamento antes de implantar a máquina virtual. Observe que o elemento copy tem o name definido como storagecopy. Além disso, o elemento dependsOn da máquina virtual também está definido como 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"],
      ...
    }
  ]
}

Nomes simbólicos podem ser usados em dependsOn matrizes. Se um nome simbólico for para um loop de cópia, todos os recursos no loop serão adicionados como dependências. O exemplo anterior pode ser gravado como o JSON a seguir. No exemplo, myVM depende de todas as contas de armazenamento no loop 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"],
      ...
    }
  }
}

Dependências circulares

O Resource Manager identifica dependências circulares durante a validação do modelo. Caso receba uma mensagem de erro devido a uma dependência circular, avalie seu modelo para conferir se é possível remover alguma dependência. Caso a remoção de dependências não funcione, será possível evitar dependências circulares migrando algumas operações de implantação para recursos filho. Implante recursos filho após recursos com dependência circular. Por exemplo, suponha que você estiver implantando duas máquinas virtuais, mas você deve definir propriedades em cada um deles que se referem a outro. Você pode implantá-los na seguinte ordem:

  1. vm1
  2. vm2
  3. Extensão na vm1 depende vm1 e vm2. A extensão define valores na vm1 que ele obtém da vm2.
  4. Extensão da vm2 depende vm1 e vm2. A extensão define valores de vm2 obtido do vm1.

Para obter informações sobre como avaliar a ordem de implantação e resolver erros de dependência, consulte Solução de erros comuns de implantação do Azure com o Azure Resource Manager.

Próximas etapas