1
votes

Provisionnement du groupe de ressources et de la fonction Azure au niveau du déploiement

J'ai rédigé le script ci-dessous pour faire ce qui suit:

  • Provisionner un groupe de ressources
  • Dans un déploiement séparé:
    • Créer un compte de stockage
    • Provisionner une batterie de serveurs
    • Mettre à disposition une application de fonction

Le problème réside dans la configuration des paramètres de l'application dans l'application de fonction, lorsque je configure AzureWebJobsStorage. La fonction resourceId ne parvient pas à résoudre le compte de stockage. Lorsque vous regardez la documentation de la fonction resourceId, elle indique:

Lorsqu'elle est utilisée avec un déploiement au niveau de l'abonnement, la fonction resourceId () ne peut récupérer que l'ID des ressources déployées à ce niveau. [docs ]

Mais maintenant je ne sais pas comment résoudre ce problème!

Modèle:

 Resource Microsoft.Storage/storageAccounts 'testStorageAccount' failed with message '{
  "error": {
    "code": "ResourceNotFound",
    "message": "The Resource 'Microsoft.Storage/storageAccounts/testStorageAccount' under resource group '<null>'
was not found."
  }
}'

Exécuté en utilisant la ligne suivante: p>

New-AzDeployment -Location "North Europe" -TemplateFile $TemplateFilePath -TemplateParameterFile $ParametersFilePath -namingPrefix $namingPrefix;

Sortie

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "resourceGroupName": {
      "type": "string"
    },
    "functionName": {
      "type": "string"
    },
    "storageAccName": {
      "type": "string"
    },
    "namingPrefix": {
      "type": "string"
    }
  },
  "variables": {
    "resourceGroupLocation": "North Europe",
    "planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
    "resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
    "functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
    "storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/resourceGroups",
      "apiVersion": "2018-05-01",
      "location": "[variables('resourceGroupLocation')]",
      "name": "[variables('resourceGroupName')]",
      "properties": {}
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2019-05-01",
      "name": "NestedTemplate",
      "resourceGroup": "[variables('resourceGroupName')]",
      "dependsOn": [
        "[variables('resourceGroupName')]"
      ],
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Storage/storageAccounts",
              "apiVersion": "2019-04-01",
              "name": "[variables('storageAccName')]",
              "location": "[variables('resourceGroupLocation')]",
              "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
              },
              "kind": "Storage",
              "properties": {
                "networkAcls": {
                  "bypass": "AzureServices",
                  "virtualNetworkRules": [],
                  "ipRules": [],
                  "defaultAction": "Allow"
                },
                "supportsHttpsTrafficOnly": true,
                "encryption": {
                  "services": {
                    "file": {
                      "enabled": true
                    },
                    "blob": {
                      "enabled": true
                    }
                  },
                  "keySource": "Microsoft.Storage"
                }
              }
            },
            {
              "type": "Microsoft.Web/serverfarms",
              "apiVersion": "2016-09-01",
              "name": "[variables('planName')]",
              "location": "[variables('resourceGroupLocation')]",
              "sku": {
                "name": "Y1",
                "tier": "Dynamic",
                "size": "Y1",
                "family": "Y",
                "capacity": 0
              },
              "kind": "functionapp",
              "properties": {
                "name": "[variables('planName')]",
                "computeMode": "Dynamic",
                "perSiteScaling": false,
                "reserved": false,
                "targetWorkerCount": 0,
                "targetWorkerSizeId": 0
              }
            },
            {
              "type": "Microsoft.Web/sites",
              "apiVersion": "2016-08-01",
              "name": "[variables('functionName')]",
              "location": "[variables('resourceGroupLocation')]",
              "dependsOn": [
                "[variables('planName')]",
                "[variables('appInsightsName')]",
                "[variables('storageAccName')]"
              ],
              "kind": "functionapp",
              "identity": {
                "type": "SystemAssigned"
              },
              "properties": {
                "enabled": true,
                "hostNameSslStates": [
                  {
                    "name": "[concat(variables('functionName'), '.azurewebsites.net')]",
                    "sslState": "Disabled",
                    "hostType": "Standard"
                  },
                  {
                    "name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
                    "sslState": "Disabled",
                    "hostType": "Repository"
                  }
                ],
                "siteConfig": {
                  "appSettings": [
                    {
                      "name": "AzureWebJobsStorage",
                      "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
                    },
                    {
                      "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                      "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
                    },
                    {
                      "name": "WEBSITE_CONTENTSHARE",
                      "value": "[variables('functionName')]"
                    },
                    {
                      "name": "FUNCTIONS_WORKER_RUNTIME",
                      "value": "node"
                    },
                    {
                      "name": "WEBSITE_NODE_DEFAULT_VERSION",
                      "value": "10.14.1"
                    },
                    {
                      "name": "FUNCTIONS_EXTENSION_VERSION",
                      "value": "~2"
                    }
                  ]
                },
                "serverFarmId": "[variables('planName')]",
                "reserved": false
              }
            }
          ]
        }
      }
    }
  ]
}


0 commentaires

5 Réponses :


-2
votes

Modifié -

Désolé, j'ai sauté le pistolet plus tôt, le problème est avec New-AzDeployment qui est spécifiquement pour le déploiement de ressources de niveau abonnement.

https : //docs.microsoft.com/en-us/powershell/module/az.resources/new-azdeployment? view = azps-2.7.0

Extraits du lien ci-dessus -

La cmdlet New-AzDeployment ajoute un déploiement à la portée de l'abonnement. Cela inclut les ressources que le déploiement nécessite.

Une ressource Azure est une entité Azure gérée par l'utilisateur. Une ressource peut vivre dans un groupe de ressources, tel que serveur de base de données, base de données, site Web, virtuel machine ou compte de stockage. Ou, cela peut être un niveau d'abonnement ressource, comme la définition de rôle, la définition de politique, etc.

Pour ajouter des ressources à un groupe de ressources, utilisez le New-AzResourceGroupDeployment qui crée un déploiement au niveau d'une ressource grouper. La cmdlet New-AzDeployment crée un déploiement au niveau portée de l'abonnement, qui déploie les ressources au niveau de l'abonnement.


1 commentaires

Merci pour vos commentaires. Malheureusement, cela ne devrait pas être le problème. J'ai le compte de stockage marqué comme une dépendance, et les deux sont dans le même groupe de ressources



1
votes

Les documents prêtent à confusion et ne décrivent pas comment resourceId () fonctionne à ce niveau. Il devrait vraiment dire:

Lorsqu'il est utilisé dans un déploiement au niveau de l'abonnement, resourceId () ne peut obtenir que les ID de ressources des groupes de ressources ( Microsoft.Resources / resourceGroups ), des stratégies ( Microsoft .Authorization / policyAssignments ) et les définitions de rôle ( Microsoft.Authorization / roleDefinitions ), car il s'agit de ressources spécifiques au niveau de l'abonnement.

Puisque c'est comme ça que ça marche. Plus de documentation ici < / a>.

Pour ce qui est de la façon de procéder à partir de là, vous devrez simplement déployer les groupes de ressources dans un modèle au niveau de l'abonnement et les ressources dans un autre modèle au niveau du groupe de ressources.


4 commentaires

Merci pour votre réponse. Ouais, j'ai envisagé d'avoir un déploiement au niveau de l'abonnement, puis un autre avec un niveau de ressources. Mais j'espérais tout garder dans un seul fichier de timplate, donc un seul déploiement doit être exécuté. Voulez-vous dire que c'est impossible


J'essaie de le faire fonctionner depuis une heure environ, et je ne pense pas que cela puisse être fait car listKeys nécessite en fin de compte une certaine utilisation de l'ID de ressource du compte de stockage. Pour votre référence, j'ai essayé de construire manuellement l'ID du compte de stockage en utilisant [concat ('/ subscriptions /', subscription (). SubscriptionId, '/ resourceGroups /', variables ('resourceGroupName'), '/ fournisseurs / Microsoft. Storage / storageAccounts / ', variables (' storageAccName '))] et l'utiliser dans listKeys puisque c'est ce que renvoie resourceId () , mais ce n'est pas le cas' t travailler.


Ouais! J'ai essayé ça aussi! Honte. Merci d'avoir pris le temps de l'essayer.


J'ai également lutté avec cela pendant un bon nombre d'heures, déterminé qu'il DOIT y avoir un moyen. Mais je ne pense pas qu'il y ait un moyen. Je ne peux faire fonctionner listKeys qu'en construisant manuellement l'identificateur de ressource, et ce faisant, le modèle n'a aucune connaissance de la création d'une dépendance implicite. Et, oh, peu importe ce que vous mettez en dépend. Ces ressources ne sont pas respectées. Et, oh, la façon dont vous NESTREZ vos ressources ne semble pas non plus avoir d'importance.



-1
votes

Pour tous ceux qui rencontrent ce problème à une date ultérieure (probablement moi-même), j'ai été obligé de créer le groupe de ressources dans mon script PowerShell, puis d'utiliser à la place new-AzResourceGroupDeployment.

Pour tenir compte de cela, les modifications apportées au le modèle de déploiement était minime (j'ai supprimé le groupe de ressources et j'ai élevé le modèle imbriqué d'un niveau). Cependant, j'accédais également de manière incorrecte à la clé du compte de stockage. Cela a été mis à jour dans le code ci-dessous.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "resourceGroupName": {
      "type": "string"
    },
    "functionName": {
      "type": "string"
    },
    "storageAccName": {
      "type": "string"
    },
    "namingPrefix": {
      "type": "string"
    }
  },
  "variables": {
    "resourceGroupLocation": "North Europe",
    "planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
    "resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
    "functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
    "storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "[variables('storageAccName')]",
      "location": "[variables('resourceGroupLocation')]",
      "sku": {
        "name": "Standard_LRS",
        "tier": "Standard"
      },
      "kind": "Storage",
      "properties": {
        "networkAcls": {
          "bypass": "AzureServices",
          "virtualNetworkRules": [],
          "ipRules": [],
          "defaultAction": "Allow"
        },
        "supportsHttpsTrafficOnly": true,
        "encryption": {
          "services": {
            "file": {
              "enabled": true
            },
            "blob": {
              "enabled": true
            }
          },
          "keySource": "Microsoft.Storage"
        }
      }
    },
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2016-09-01",
      "name": "[variables('planName')]",
      "location": "[variables('resourceGroupLocation')]",
      "sku": {
        "name": "Y1",
        "tier": "Dynamic",
        "size": "Y1",
        "family": "Y",
        "capacity": 0
      },
      "kind": "functionapp",
      "properties": {
        "name": "[variables('planName')]",
        "computeMode": "Dynamic",
        "perSiteScaling": false,
        "reserved": false,
        "targetWorkerCount": 0,
        "targetWorkerSizeId": 0
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2016-08-01",
      "name": "[variables('functionName')]",
      "location": "[variables('resourceGroupLocation')]",
      "dependsOn": [
        "[variables('planName')]",
        "[variables('appInsightsName')]",
        "[variables('storageAccName')]"
      ],
      "kind": "functionapp",
      "identity": {
        "type": "SystemAssigned"
      },
      "properties": {
        "enabled": true,
        "hostNameSslStates": [
          {
            "name": "[concat(variables('functionName'), '.azurewebsites.net')]",
            "sslState": "Disabled",
            "hostType": "Standard"
          },
          {
            "name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
            "sslState": "Disabled",
            "hostType": "Repository"
          }
        ],
        "siteConfig": {
          "appSettings": [
            {
              "name": "AzureWebJobsStorage",
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
            },
            {
              "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
            },
            {
              "name": "WEBSITE_CONTENTSHARE",
              "value": "[variables('functionName')]"
            },
            {
              "name": "FUNCTIONS_WORKER_RUNTIME",
              "value": "node"
            },
            {
              "name": "WEBSITE_NODE_DEFAULT_VERSION",
              "value": "10.14.1"
            },
            {
              "name": "FUNCTIONS_EXTENSION_VERSION",
              "value": "~2"
            }
          ]
        },
        "serverFarmId": "[variables('planName')]",
        "reserved": false
      }
    }
  ]
}
$resourceGroup = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
    if(!$resourceGroup)
    {
        Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
        New-AzResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
    }
    else{
        Write-Host "Using existing resource group '$resourceGroupName'";
    }

    # Start the deployment
    Write-Host "Starting deployment...";
    if(Test-Path $parametersFilePath) {
        New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterFile $parametersFilePath;
    }


0 commentaires

2
votes

Vous avez rencontré quelques «limitations» dans le langage des modèles qui rendent cela difficile pour le moment (nous travaillons à améliorer les deux).

1) Les déploiements imbriqués Inline ont la portée du déploiement de niveau supérieur lors de l'évaluation des expressions de langage de modèle (n'importe quoi entre []), ce qui est parfois pratique (vous pouvez partager des variables par exemple) mais plus souvent que pas cause un problème (comme la fonction resourceId). ARM s'est toujours comporté de cette façon, mais avec l'avènement des déploiements au niveau des abonnements, c'est un peu plus problématique (vous y rencontrez plus). Pour contourner ce problème, vous pouvez utiliser des modèles liés - je sais que ce n'est pas toujours idéal, mais ils se comporteront comme prévu.

2) la deuxième chose que vous rencontrez est que les fonctions list * () sont évaluées immédiatement si ARM pense que la ressource à laquelle vous accédez ne fait pas partie du même déploiement. En raison du n ° 1, c'est ce que pense ARM dans ce cas et pourquoi essayer de concat () le resourceID ne fonctionne toujours pas.

En dehors de cela, éloignez-vous de la fonction provider () pour les apiVersions, ce n'est pas déterministe et les résultats de cette fonction peuvent changer sans que vous le sachiez. Le code que vous aviez dans votre article d'origine pour listKeys fonctionnait il y a quelque temps et vous le verrez peut-être dans des exemples flottants, mais des changements dans la plate-forme peuvent briser le comportement de cette fonction. Les apiVersions littérales sont toujours meilleures dans les modèles ARM.


2 commentaires

Merci pour votre réponse. Ouais, nicher en ligne n'était probablement pas la chose la plus intelligente, mais j'essayais juste de le faire fonctionner! Je suis d'accord sur la fonction fournisseurs (). Je ne faisais que le tester. Ont été mordus une fois de trop en obtenant les dernières nouvelles de NPM!


Honnêtement, l'imbrication est une excellente idée, elle est juste interrompue pour tout ce qui va au-delà des scénarios Hello World - espérons que cela sera bientôt corrigé.