Definición del orden de implementación de recursos en las plantillas de ARM

Al implementar recursos, es posible que tenga que asegurarse de que existen algunos recursos antes de crear otros. Por ejemplo, necesitará un servidor SQL lógico para poder implementar una base de datos. Establezca esta relación marcando un recurso como dependiente de otro recurso. Use el elemento dependsOn para definir una dependencia explícita. Utilice las funciones reference o list para definir una dependencia implícita.

Azure Resource Manager evalúa las dependencias entre recursos y los implementa en su orden dependiente. Cuando no hay recursos dependientes entre sí, Resource Manager los implementa en paralelo. Solo tiene que definir las dependencias de recursos que se implementan en la misma plantilla.

Sugerencia

Se recomienda Bicep porque ofrece las mismas funcionalidades que las plantillas de ARM y la sintaxis es más fácil de usar. Para obtener más información, consulte dependencias de recursos.

dependsOn

Dentro de la plantilla de Azure Resource Manager, el elemento dependsOn permite definir un recurso como dependiente de uno o más recursos. Su valor es una matriz de cadenas de notación de objetos JavaScript (JSON), cada una de las cuales es un nombre o identificador de recurso. La lista puede incluir recursos que se implementan condicionalmente. Cuando un recurso condicional no está implementado, Azure Resource Manager lo quita automáticamente de las dependencias necesarias.

En el ejemplo siguiente se muestra una interfaz de red que depende de una red virtual, un grupo de seguridad de red y una dirección IP pública. Para ver la plantilla completa, consulte la plantilla de inicio rápido de una máquina virtual 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'))]"
  ],
  ...
}

Con languageVersion 2.0, use el nombre simbólico del recurso en matrices dependsOn. Por ejemplo:

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

Si bien puede que se sienta tentado a usar dependsOn para asignar relaciones entre los recursos, es importante comprender por qué lo hace. Por ejemplo, para documentar cómo están interconectados los recursos, dependsOn no es el enfoque correcto. Después de la implementación, el recurso no conserva las dependencias de implementación en sus propiedades, por lo que no hay ningún comando u operación que le permita ver las dependencias. La configuración de dependencias innecesarias reduce el tiempo de implementación porque Resource Manager no puede implementar esos recursos en paralelo.

Recursos secundarios

Una dependencia de implementación implícita no se crea automáticamente entre un recurso secundario y el primario. Si necesita implementar el recurso secundario después del primario, establezca la propiedad dependsOn.

En el siguiente ejemplo se muestran un servidor SQL lógico y una base de datos. Observe que se ha definido una dependencia explícita entre la base de datos y el servidor, a pesar de que la base de datos es un elemento secundario del 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 ver la plantilla completa, consulte la plantilla de inicio rápido para Azure SQL Database.

Funciones de referencia y lista

La función reference permite que una expresión derive su valor de otros pares de valor y nombre JSON o de recursos en tiempo de ejecución. Las funciones list* devuelven valores para un recurso de una operación de lista.

Las expresiones de referencia y lista declaran implícitamente que un recurso depende de otro. Siempre que sea posible, use una referencia implícita para evitar agregar una dependencia innecesaria.

Para aplicar una dependencia implícita, haga referencia al recurso por su nombre, y no por el identificador de recurso. Si se pasa el identificador de recurso a las funciones de referencia o lista, no se crea una referencia implícita.

El formato general de la función reference es:

reference('resourceName').propertyPath

El formato general de la función listKeys es:

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

En el ejemplo siguiente, un punto de conexión de CDN depende explícitamente del perfil de CDN e implícitamente de una aplicación web.

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

Para más información, consulte función reference.

Dependencia de los recursos de un bucle

Para implementar recursos que dependen de recursos en un bucle de copia, tiene dos opciones. Puede establecer una dependencia de recursos individuales dentro del bucle o de todo el bucle.

Nota:

En la mayoría de los escenarios, debe establecer la dependencia de recursos específicos dentro del bucle de copia. Dependa solo del bucle entero cuando necesite que todos los recursos del bucle existan antes de crear el recurso siguiente. Al establecer la dependencia de todo el bucle, el grafo de dependencias se expande de forma significativa, especialmente si esos recursos del bucle dependen de otros recursos. Las dependencias expandidas dificultan que la implementación se complete de forma eficaz.

En el ejemplo siguiente se muestra cómo implementar varias máquinas virtuales. La plantilla crea el mismo número de interfaces de red. Cada máquina virtual depende de una interfaz de red, en lugar de todo el bucle.

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

En el ejemplo siguiente, se muestra cómo se implementan tres cuentas de almacenamiento antes de implementar la máquina virtual. Observe que el elemento copy tiene name establecido en storagecopy y el elemento dependsOn de la máquina virtual también está establecido en 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"],
      ...
    }
  ]
}

Los nombres simbólicos se pueden usar en matrices dependsOn. Si un nombre simbólico es para un bucle de copia, todos los recursos del bucle se agregan como dependencias. El ejemplo anterior se puede escribir como el siguiente JSON. En el ejemplo, myVM depende de todas las cuentas de almacenamiento del bucle 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"],
      ...
    }
  }
}

Dependencias circulares

Resource Manager identifica dependencias circulares durante la validación de plantillas. Si recibe un error en una dependencia circular, evalúe la plantilla para ver si se puede quitar alguna dependencia. Si no es suficiente con quitar dependencias, puede evitar dependencias circulares moviendo algunas operaciones de implementación a recursos secundarios. Implemente los recursos secundarios después de los recursos que tienen la dependencia circular. Por ejemplo, suponga que va a implementar dos máquinas virtuales pero debe establecer propiedades en cada una que hagan referencia a la otra. Puede implementarlas en el orden siguiente:

  1. vm1
  2. vm2
  3. La extensión en vm1 depende de vm1 y vm2. La extensión establece valores en vm1 que obtiene de vm2.
  4. La extensión en vm2 depende de vm1 y vm2. La extensión establece valores en vm2 que obtiene de vm1.

Para información sobre cómo evaluar el orden de implementación y resolver errores de dependencia, consulte Solución de errores comunes de implementación de Azure con Azure Resource Manager.

Pasos siguientes