如何使用包含资源组和资源的链接模板部署 Arm 模板

How to deploy a Arm template with Linked template that contains a resource group and resources

我有一个 'grandparent' 主模板,它部署了另一个链接的 'parent' 模板 4 次,每次使用不同的组名(我只显示了第一个资源):

{
    "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "resourcegroupName": {
            "type": "string",
            "metadata": {
                "description": "The name given to the group and all resources it contains by default"
            }
        },
        "resourceGroupLocation": {
            "type": "string",
            "metadata": {
                "description": "The Location of the resource group"
            }
        },
        "templateFolderUri": {
            "type": "string",
            "metadata": {
                "description": "The URI of the template component folder"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [
        {
            "name": "[concat(parameters('resourceGroupName'), 'Dev')]",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2021-04-01",
            "location": "[parameters('resourceGroupLocation')]",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('templateFolderUri'), '/completeNovaRssDeploy.json')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {
                    "resourcegroupName": "[concat(parameters('resourcegroupName'), 'Dev')]",
                    "resourceGroupLocation": "[parameters('resourceGroupLocation')]",
                    "templateFolderUri": "[concat(parameters('resourcegroupName'), '/Components')]"
                }
            }
        },

        <resource repeated 3 times>

    ],
    "outputs": {}
}

'parent' 模板,还链接其他 'child' 模板,如下所示:

{
    "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "resourcegroupName": {
            "type": "string",
            "metadata": {
                "description": "The name given to the group and all resources it contains by default"
            }
        },
        "resourceGroupLocation": {
            "type": "string",
            "metadata": {
                "description": "The Location of the resource group"
            }
        },
        "templateFolderUri": {
            "type": "string",
            "metadata": {
                "description": "The URI of the template component folder"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [
        {
            "comments": "Template for creating the resource group",
            "name": "[parameters('resourcegroupName')]",
            "type": "Microsoft.Resources/resourceGroups",
            "apiVersion": "2021-04-01",
            "location": "[parameters('resourceGroupLocation')]",
            "properties": {}
            
        
        },
        {
            "name": "[parameters('resourceGroupName')]",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "[parameters('resourcegroupName')]",
            "apiVersion": "2021-04-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('templateFolderUri'), '/servicePlanCreator.json')]",
                    "contentVersion": "1.0.0.0"
                }
            }, 
            "dependsOn": [
                "[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]"
            ]
        },
        {
            "name": "[concat(parameters('resourceGroupName'), 'Storage')]",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "[parameters('resourcegroupName')]",
            "apiVersion": "2021-04-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('templateFolderUri'), '/storageAccountTemplate.json')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {}
            },
            "dependsOn": [
                "[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]"
            ]
        },
        {
            "name": "[concat(parameters('resourceGroupName'), 'Vault')]",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "[parameters('resourcegroupName')]",
            "apiVersion": "2021-04-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('templateFolderUri'), '/keyVaultCreator.json')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {}
            },
            "dependsOn": [
                "[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]"
            ]
        },
        {
            "name": "[concat(parameters('resourceGroupName'), 'App')]",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "[parameters('resourcegroupName')]",
            "apiVersion": "2021-04-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[concat(parameters('templateFolderUri'), '/dualSlotWebApp.json')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters": {}
            },
            "dependsOn": [
                "[resourceId('Microsoft.Resources/resourceGroups/', parameters('resourceGroupName'))]",
                "[resourceId('Microsoft.Resources/deployments', parameters('resourceGroupName'))]"
            ]
        }
    ],
    "outputs": {}
}

'parent' 模板在 运行 独立时有效,父模板无效。 g运行dparent 模板中每个资源的类型出现错误:

##[error]Multiple error occurred: BadRequest,BadRequest,BadRequest,BadRequest. Please see details.
##[error]Details:
##[error]InvalidTemplate: The nested deployment 'NovaArmTestDev' failed validation: 'Error converting value "NovaArmTestDev" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 476.'.
##[error]InvalidTemplate: The nested deployment 'NovaArmTestTest' failed validation: 'Error converting value "NovaArmTestTest" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 479.'.
##[error]InvalidTemplate: The nested deployment 'NovaArmTestCat' failed validation: 'Error converting value "NovaArmTestCat" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 476.'.
##[error]InvalidTemplate: The nested deployment 'NovaArmTest' failed validation: 'Error converting value "NovaArmTest" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 467.'.
##[warning]Validation errors were found in the Azure Resource Manager template. This can potentially cause template deployment to fail. Task failed while creating or updating the template deployment.. Please follow https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-syntax
Starting Deployment.
Deployment name is completeNovaRssDeploy-20220527-130154-2824
There were errors in your deployment. Error code: DeploymentFailed.
##[error]At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.
##[error]Details:
##[error]InvalidRequestContent: The request content was invalid and could not be deserialized: 'Error converting value "NovaArmTest" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 266.'.
##[error]InvalidRequestContent: The request content was invalid and could not be deserialized: 'Error converting value "NovaArmTestCat" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 269.'.
##[error]InvalidRequestContent: The request content was invalid and could not be deserialized: 'Error converting value "NovaArmTestDev" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 269.'.
##[error]InvalidRequestContent: The request content was invalid and could not be deserialized: 'Error converting value "NovaArmTestTest" to type 'Azure.Deployments.Core.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.resourcegroupName', line 1, position 270.'.
##[error]Check out the troubleshooting guide to see if your issue is addressed: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/deploy/azure-resource-group-deployment?view=azure-devops#troubleshooting
##[error]Task failed while creating or updating the template deployment.

我相信我理解为什么会发生这种情况,因为在 'grandparent' 模板中我将 'parent' 链接为 "type": "Microsoft.Resources/deployments" 当 'parent' 模板部署资源组并且在订阅范围内操作。我也尝试将类型设置为 "type": "Microsoft.Resources/resourceGroups" 但这也不起作用。我相信这可以通过将资源组从 'parent' 模板移动到 'grandparent' 来解决,但我想知道是否有一种资源类型可以更轻松地在同一个链接模板中容纳这两种类型。

将参数传递给链接模板时,参数需要额外添加 属性,称为 "value": ...

修复所提供示例的一部分,结果如下

...
        "parameters": {
          "resourcegroupName": {
            "value": "[concat(parameters('resourcegroupName'), 'Dev')]"
          },
          "resourceGroupLocation": {
            "value": "[parameters('resourceGroupLocation')]"
          },
          "templateFolderUri": {
            "value": "[concat(parameters('templateFolderUri'), '/Components')]"
          }
        }
...

参考:https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/linked-templates?tabs=azure-powershell#:~:text=To%20pass%20parameter%20values%20inline