在部署级别配置资源组和Azure功能

时间:2019-09-26 10:23:46

标签: json azure azure-resource-manager azure-deployment

我已经编写了以下脚本来执行以下操作:

  • 提供资源组
  • 在单独的部署中:
    • 提供存储帐户
    • 提供服务器场
    • 提供功能应用

问题在于我设置AzureWebJobsStorage时在功能应用程序中的应用程序设置的设置。 resourceId函数无法解析存储帐户。在查看resourceId函数的文档时,它指出:

  

与预订级别的部署一起使用时,resourceId()函数只能检索在该级别部署的资源的ID。 edit this answer

但是现在我不知道该如何解决!

模板:

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

使用以下行执行:

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

输出

 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."
  }
}'

5 个答案:

答案 0 :(得分:2)

您在模板语言中遇到了一些“局限性”,这些局限性使得目前这一点变得困难(我们正在努力改进两者)。

1)在评估模板语言表达式([]中的任何内容)时,内联嵌套部署具有顶级部署的范围,这有时很方便(例如,您可以共享变量),但更常见不会造成一些问题(例如resourceId函数)。 ARM一直都是这种方式,但是随着订阅级部署的到来,这会带来更多问题(您会遇到更多问题)。为了解决这个问题,您可以使用链接的模板-我知道这并不总是理想的,但是它们的行为会达到预期。

2)您遇到的第二件事是,如果ARM认为您正在访问的资源不在同一部署中,则会立即评估list *()函数。由于#1,这就是ARM在这种情况下的想法,并且为什么尝试concat()resourceID仍然不起作用。

除此之外,请远离apiVersions的provider()函数,它不是确定性的,该函数的结果可能会在您不知不觉中发生变化。您在原始文章中用于listKeys的代码已经工作了一段时间,您可能会在示例中看到它,但是平台的更改可能会破坏该函数的行为。在api模板中,文字apiVersions总是更好。

答案 1 :(得分:1)

文档令人困惑,没有描述resourceId()在该级别上的工作方式。它应该真的说:

  

在预订级别的部署中使用时,resourceId()只能获取资源组(Microsoft.Resources/resourceGroups),策略(Microsoft.Authorization/policyAssignments)和角色定义(Microsoft.Authorization/roleDefinitions的资源ID。 ),因为这些是订阅级别的特定资源。

因为这是实际的工作方式。 More docs here

关于如何从此处进行操作,您只需要在预订级别将一个资源模板部署在一个模板中,而在资源组级别将另一个模板部署在资源。

答案 2 :(得分:0)

我遇到了这个问题,发现它们最近通过在部署资源和函数作用域上定义内部和外部作用域,更好地支持嵌套模板。

https://docs.microsoft.com/bs-latn-ba/azure/azure-resource-manager/templates/cross-scope-deployment?tabs=azure-cli#how-functions-resolve-in-scopes

https://www.youtube.com/watch?v=96XxVyxrhZI

答案 3 :(得分:-1)

对于以后遇到此问题的任何人(可能是我自己),我被迫在Powershell脚本中创建资源组,然后改用new-AzResourceGroupDeployment。

为适应这种情况,对部署模板的更改很小(我删除了资源组并将嵌套模板提高了一层)。但是,我也错误地访问了存储帐户密钥。在下面的代码中已对此进行了更新。

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

答案 4 :(得分:-2)

已编辑-

对不起,我较早前提出了建议,问题出在New-AzDeployment上,它专门用于部署订阅级资源。

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

上面链接的摘录-

  

New-AzDeployment cmdlet在当前位置添加一个部署   订阅范围。这包括部署所需的资源   要求。

     

Azure资源是用户管理的Azure实体。资源可以生存   在资源组中,例如数据库服务器,数据库,网站,虚拟   机器或存储帐户。或者,它可以是订阅级别   资源,例如角色定义,策略定义等。

     

要将资源添加到资源组,请使用   New-AzResourceGroupDeployment在资源上创建部署   组。 New-AzDeployment cmdlet在当前位置创建一个部署   订阅范围,用于部署订阅级资源。