Itération de ressource dans les modèles ARM

Cet article explique comment créer plusieurs instances d’une ressource dans votre modèle Azure Resource Manager (modèle ARM). En ajoutant copy loop à la section resources de votre modèle, vous pouvez définir de façon dynamique le nombre de ressources à déployer. Cela vous évite également de répéter la syntaxe du modèle.

Vous pouvez également utiliser copy loop avec les éléments properties, variables et outputs.

Si vous devez spécifier si une ressource est déployée, consultez la page relative à l’élément Condition.

Conseil

Nous recommandons Bicep, parce qu’il offre les mêmes fonctionnalités que les modèles ARM et que la syntaxe est plus facile d’utilisation. Pour en savoir plus, consultez Boucles.

Syntaxe

Ajoutez l’élément copy à la section resources de votre modèle pour déployer plusieurs instances de la ressource. L’élément copy utilise le format général suivant :

"copy": {
  "name": "<name-of-loop>",
  "count": <number-of-iterations>,
  "mode": "serial" <or> "parallel",
  "batchSize": <number-to-deploy-serially>
}

La propriété name est toute valeur qui identifie la boucle. La propriété count spécifie le nombre d’itérations que vous souhaitez pour le type de ressource.

Utilisez les propriétés mode et batchSize pour spécifier si les ressources sont déployées en parallèle ou en séquence. Ces propriétés sont décrites dans Série ou parallèle.

Limites de copie

Le nombre ne peut pas dépasser 800.

Le nombre ne peut pas être négatif. Il peut être zéro si vous déployez le modèle avec une version récente d’Azure CLI, de PowerShell ou de l’API REST. Plus précisément, vous devez utiliser :

  • Azure PowerShell 2.6 ou version ultérieure
  • Azure CLI 2.0.74 ou version ultérieure
  • API REST version 2019-05-10 ou ultérieure
  • Les déploiements liés doivent utiliser la version 2019-05-10 de l’API ou une version ultérieure pour le type de ressource de déploiement

Les versions antérieures de PowerShell, de l’interface CLI et de l’API REST ne prennent pas en charge le nombre zéro.

Soyez prudent lorsque vous utilisez un déploiement en mode complet avec un boucle de copie. Si vous redéployez dans un groupe de ressources en mode Complet, toutes les ressources qui ne sont pas spécifiées dans le modèle après la résolution de la boucle de copie sont supprimées.

Itération de ressource

L’exemple suivant crée le nombre de comptes de stockage spécifiés dans le paramètre storageCount.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "storageCount": {
      "type": "int",
      "defaultValue": 3
    }
  },
  "resources": [
    {
      "copy": {
        "name": "storagecopy",
        "count": "[length(range(0, parameters('storageCount')))]"
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}', range(0, parameters('storageCount'))[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

Notez que le nom de chaque ressource inclut la fonction copyIndex(), qui renvoie l’itération actuelle de la boucle. copyIndex() est basé sur zéro. Si bien que l’exemple suivant :

"name": "[format('storage{0}', copyIndex())]",

Crée les noms suivants :

  • storage0
  • storage1
  • storage2

Pour décaler la valeur d’index, vous pouvez passer une valeur dans la fonction copyIndex(). Le nombre d’itérations est toujours spécifié dans l’élément copy, mais la valeur de copyIndex est décalée en fonction de la valeur spécifiée. Si bien que l’exemple suivant :

"name": "[format('storage{0}', copyIndex(1))]",

Crée les noms suivants :

  • storage1
  • storage2
  • storage3

L’opération copy se révèle utile lorsque vous travaillez avec des tableaux, car vous pouvez itérer sur chaque élément du tableau. Utilisez la fonction length sur le tableau pour spécifier le nombre d’itérations, et copyIndex pour récupérer l’index actuel dans le tableau.

L’exemple suivant crée un compte de stockage par nom fourni dans le paramètre.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageNames": {
      "type": "array",
      "defaultValue": [
        "contoso",
        "fabrikam",
        "coho"
      ]
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "copy": {
        "name": "storagecopy",
        "count": "[length(parameters('storageNames'))]"
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}{1}', parameters('storageNames')[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

Si vous souhaitez retourner des valeurs à partir des ressources déployées, vous pouvez utiliser l’élément copy dans la section outputs.

Utiliser un nom symbolique

Le nom symbolique est attribué aux boucles de copie de ressources. L’index de boucle est basé sur zéro. Dans l’exemple suivant, myStorages[1] fait référence à la deuxième ressource de la boucle de ressources.

{
  "$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]"
    },
    "storageCount": {
      "type": "int",
      "defaultValue": 2
    }
  },
  "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",
      "properties": {},
      "copy": {
        "name": "storagecopy",
        "count": "[parameters('storageCount')]"
      }
    }
  },
  "outputs": {
    "storageEndpoint":{
      "type": "object",
      "value": "[reference('myStorages[1]').primaryEndpoints]"
    }
  }
}

Si l’index est une valeur d’exécution, mettez en forme la référence vous-même. Par exemple

"outputs": {
  "storageEndpoint":{
    "type": "object",
    "value": "[reference(format('myStorages[{0}]', variables('runtimeIndex'))).primaryEndpoints]"
  }
}

Les noms symboliques peuvent être utilisés dans les tableaux dependsOn. Si un nom symbolique est pour une boucle de copie, toutes les ressources de la boucle sont ajoutées en tant que dépendances. Pour plus d’informations, consultez Dépend des ressources dans une boucle.

Série ou parallèle

Par défaut, Resource Manager crée les ressources en parallèle. Il n’applique aucune limite au nombre de ressources déployées en parallèle, à l’exception de la limite totale de 800 ressources dans le modèle. L’ordre de création n’est pas garanti.

Toutefois, vous souhaiterez peut-être spécifier que les ressources soient déployées en séquence. Par exemple, lors de la mise à jour d’un environnement de production, vous souhaiterez échelonner les mises à jour afin que seulement un certain nombre soient mises à jour à un moment donné.

Pour déployer en série plusieurs instances d’une ressource, affectez à mode la valeur mode et à batchSize le nombre d’instances à déployer à la fois. Avec le mode série, Resource Manager crée une dépendance sur les instances précédentes de la boucle, afin de ne pas démarrer un lot tant que le précédent n’est pas terminé.

La valeur de batchSize ne peut pas dépasser la valeur de count dans l’élément copy.

{
  "$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": [
    {
      "copy": {
        "name": "storagecopy",
        "count": 4,
        "mode": "serial",
        "batchSize": 2
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}', range(0, 4)[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

La propriété mode accepte également mode, qui est la valeur par défaut.

Itération d’une ressource enfant

Vous ne pouvez pas utiliser une boucle de copie pour une ressource enfant. Pour créer plusieurs instances d’une ressource que l’on définit en général comme imbriquée dans une autre ressource, vous devez au contraire la créer sous la forme d’une ressource de premier niveau. Vous définissez la relation avec la ressource parente par le biais des propriétés type et name.

Par exemple, supposons que vous définissez généralement un jeu de données comme une ressource enfant dans une fabrique de données.

{
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories",
      "name": "exampleDataFactory",
      ...
      "resources": [
        {
          "type": "datasets",
          "name": "exampleDataSet",
          "dependsOn": [
            "exampleDataFactory"
          ],
          ...
        }
      ]
      ...
    }
  ]
}

Pour créer plusieurs jeux de données, déplacez-le en dehors de la fabrique de données. Le jeu de données doit être au même niveau que la fabrique de données, mais il est toujours une ressource enfant de la fabrique de données. Vous conservez la relation entre le jeu de données et la fabrique de données par le biais des propriétés type et name. Étant donné que le type ne peut plus peut être déduit à partir de sa position dans le modèle, vous devez fournir le type qualifié complet au format : {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}.

Pour établir une relation parent/enfant avec une instance de la fabrique de données, fournissez un nom pour le jeu de données incluant le nom de la ressource parente. Utilisez le format : {parent-resource-name}/{child-resource-name}.

L’exemple suivant illustre l’implémentation.

"resources": [
{
  "type": "Microsoft.DataFactory/factories",
  "name": "exampleDataFactory",
  ...
},
{
  "type": "Microsoft.DataFactory/factories/datasets",
  "name": "[format('exampleDataFactory/exampleDataSet{0}', copyIndex())]",
  "dependsOn": [
    "exampleDataFactory"
  ],
  "copy": {
    "name": "datasetcopy",
    "count": "3"
  },
  ...
}]

Exemples de modèles

Les exemples suivants montrent des scénarios courants de création de plusieurs instances d’une ressource ou d’une propriété.

Modèle Description
Copie de stockage Déploie plusieurs comptes de stockage dont le nom comporte un numéro d’index .
Copie de stockage en série Déploie plusieurs comptes de stockage un par un. Le nom inclut le numéro d’index.
Copie de stockage avec tableau Déploie plusieurs comptes de stockage. Le nom contient une valeur tirée d’un tableau.
Copie de groupe de ressources Déploie plusieurs groupes de ressources.

Étapes suivantes