教程:部署链接模板Tutorial: Deploy a linked template

前一篇教程已介绍如何部署存储在本地计算机中的模板。In the previous tutorials, you learned how to deploy a template that is stored in your local computer. 若要部署复杂的解决方案,可将一个模板分解为多个模板,并通过主模板部署这些模板。To deploy complex solutions, you can break a template into many templates, and deploy these templates through a main template. 本教程介绍如何部署包含对链接模板的引用的主模板。In this tutorial, you learn how to deploy a main template that contains the reference to a linked template. 部署主模板时,会触发链接模板的部署。When the main template gets deployed, it triggers the deployment of the linked template. 本教程还将介绍如何使用 SAS 令牌来存储和保护链接模板。You also learn how to store and secure the linked template by using SAS token. 完成该过程需要大约 12 分钟It takes about 12 minutes to complete.

先决条件Prerequisites

建议完成前一篇教程,但这不是一项要求。We recommend that you complete the previous tutorial, but it's not required.

审阅模板Review template

在前面的教程中,你部署了一个用于创建存储帐户、应用服务计划和 Web 应用的模板。In the previous tutorials, you deploy a template that creates a storage account, App Service plan, and web app. 使用的模板是:The template used was:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 11,
      "metadata": {
        "description": "Specify a project name that is used to generate resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "storageSKU": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Premium_LRS",
      ],
      "metadata": {
        "description": "Specify the storage account type."
      }
    },
    "linuxFxVersion": {
      "type": "string",
      "defaultValue": "php|7.0",
      "metadata": {
        "description": "Specify the Runtime stack of current web app"
      }
    }
  },
  "variables": {
    
    "storageAccountName": "[concat(parameters('projectName'), uniqueString(resourceGroup().id))]",
    "webAppName": "[concat(parameters('projectName'), 'WebApp')]",
    "appServicePlanName": "[concat(parameters('projectName'), 'Plan')]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('storageSKU')]"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    },
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2016-09-01",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "B1",
        "tier": "Basic",
        "size": "B1",
        "family": "B",
        "capacity": 1
      },
      "kind": "linux",
      "properties": {
        "perSiteScaling": false,
        "reserved": true,
        "targetWorkerCount": 0,
        "targetWorkerSizeId": 0
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2018-11-01",
      "name": "[variables('webAppName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ],
      "kind": "app",
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "siteConfig": {
          "linuxFxVersion": "[parameters('linuxFxVersion')]"
        }
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference(variables('storageAccountName')).primaryEndpoints]"
    }
  }
}

创建链接模板Create a linked template

可将存储帐户资源隔离到链接模板中:You can separate the storage account resource into a linked template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountEndPoint": "https://core.chinacloudapi.cn/",
    "storageAccountName": {
      "type": "string",
      "metadata": {
        "description": "Specify the storage account name."
      }
    },
    "location": {
      "type": "string",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "storageSKU": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Premium_LRS",
      ],
      "metadata": {
        "description": "Specify the storage account type."
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('storageSKU')]"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference(parameters('storageAccountName')).primaryEndpoints]"
    }
  }
}

以下模板是主模板。The following template is the main template. 突出显示的 Microsoft.Resources/deployments 对象演示如何调用链接模板。The highlighted Microsoft.Resources/deployments object shows how to call a linked template. 无法将链接模板存储为本地文件,或存储为只能在本地网络中使用的文件。The linked template cannot be stored as a local file or a file that is only available on your local network. 只能提供包含 HTTP 或 HTTPS 的 URI 值。You can only provide a URI value that includes either HTTP or HTTPS. 资源管理器必须能够访问该模板。Resource Manager must be able to access the template. 一种做法是将链接模板放入存储帐户,并对该项使用 URI。One option is to place your linked template in a storage account, and use the URI for that item. 该 URI 将通过参数传递给模板。The URI is passed to template using a parameter. 请参阅突出显示的参数定义。See the highlighted parameter definition.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 11,
      "metadata": {
        "description": "Specify a project name that is used to generate resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "linuxFxVersion": {
      "type": "string",
      "defaultValue": "php|7.0",
      "metadata": {
        "description": "The Runtime stack of current web app"
      }
    },
    "linkedTemplateUri": {
      "type": "string",
      "metadata": {
        "description": "The Uri of the linked template."
      }
    }
  },
  "variables": {
    "storageAccountEndPoint": "https://core.chinacloudapi.cn/",
    "storageAccountName": "[concat(parameters('projectName'), uniqueString(resourceGroup().id))]",
    "webAppName": "[concat(parameters('projectName'), 'WebApp')]",
    "appServicePlanName": "[concat(parameters('projectName'), 'Plan')]"
  },
  "resources": [
    {
      "name": "linkedTemplate",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2018-05-01",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[parameters('linkedTemplateUri')]"
        },
        "parameters": {
          "storageAccountEndPoint": "https://core.chinacloudapi.cn/",
          "storageAccountName": {
            "value": "[variables('storageAccountName')]"
          },
          "location": {
            "value": "[parameters('location')]"
          }
        }
      }
    },
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2016-09-01",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "B1",
        "tier": "Basic",
        "size": "B1",
        "family": "B",
        "capacity": 1
      },
      "kind": "linux",
      "properties": {
        "perSiteScaling": false,
        "reserved": true,
        "targetWorkerCount": 0,
        "targetWorkerSizeId": 0
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2018-11-01",
      "name": "[variables('webAppName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ],
      "kind": "app",
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "siteConfig": {
          "linuxFxVersion": "[parameters('linuxFxVersion')]"
        }
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference('linkedTemplate').outputs.storageEndpoint.value]"
    }
  }
}

将主模板的副本保存到扩展名为 .json 的本地计算机,例如 azuredeploy.json 。Save a copy of the main template to your local computer with the .json extension, for example, azuredeploy.json. 无需保存链接模板的副本。You don't need to save a copy of the linked template. 链接模板将从 GitHub 存储库复制到存储帐户。The linked template will be copied from a GitHub repository to a storage account.

存储链接模板Store the linked template

以下 PowerShell 脚本将创建存储帐户,创建容器,然后将链接模板从 GitHub 存储库复制到该容器。The following PowerShell script creates a storage account, creates a container, and copies the linked template from a GitHub repository to the container. 链接模板的副本存储在 GitHub 中。A copy of the linked template is stored in GitHub.

重要

存储帐户名称长度必须为 3 到 24 个字符,并且只能使用数字和小写字母。Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only. 该名称必须是唯一的。The name must be unique. 在模板中,存储帐户名称是追加了“store”的项目名称,项目名称的长度必须介于 3 到 11 个字符之间。In the template, the storage account name is the project name with store appended, and the project name must be between 3 and 11 characters. 因此,项目名称必须符合存储帐户名称要求,且短于 11 个字符。So the project name must meet the storage account name requirements and has less than 11 characters.

$projectName = Read-Host -Prompt "Enter a project name:"   # This name is used to generate names for Azure resources, such as storage account name.
$location = Read-Host -Prompt "Enter a location (i.e. chinaeast)"

$resourceGroupName = $projectName + "rg"
$storageAccountName = $projectName + "store"
$containerName = "templates" # The name of the Blob container to be created.

$linkedTemplateURL = "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-deployment/linked-template/linkedStorageAccount.json" # A completed linked template used in this tutorial.
$fileName = "linkedStorageAccount.json" # A file name used for downloading and uploading the linked template.

# Download the template
Invoke-WebRequest -Uri $linkedTemplateURL -OutFile "$home/$fileName"

# Create a resource group
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Create a storage account
$storageAccount = New-AzStorageAccount `
    -ResourceGroupName $resourceGroupName `
    -Name $storageAccountName `
    -Location $location `
    -SkuName "Standard_LRS"

$context = $storageAccount.Context

# Create a container
New-AzStorageContainer -Name $containerName -Context $context -Permission Container

# Upload the template
Set-AzStorageBlobContent `
    -Container $containerName `
    -File "$home/$fileName" `
    -Blob $fileName `
    -Context $context

Write-Host "Press [ENTER] to continue ..."

部署模板Deploy template

要在存储帐户中部署专用模板,请生成 SAS 令牌,并将其包括在模板的 URI 中。To deploy a private template in a storage account, generate a SAS token and include it in the URI for the template. 设置到期时间以允许足够的时间来完成部署。Set the expiry time to allow enough time to complete the deployment. 只有帐户所有者才能访问包含该模板的 Blob。The blob containing the template is accessible to only the account owner. 但是,如果为 blob 创建 SAS 令牌,则拥有该 URI 的任何人都可以访问 blob。However, when you create a SAS token for the blob, the blob is accessible to anyone with that URI. 如果其他用户截获了该 URI,则此用户可以访问该模板。If another user intercepts the URI, that user is able to access the template. 使用 SAS 令牌是限制对模板的访问的好办法,但不应直接在模板中包括密码等敏感数据。A SAS token is a good way of limiting access to your templates, but you should not include sensitive data like passwords directly in the template.

如果尚未创建资源组,请参阅创建资源组If you haven't created the resource group, see Create resource group.

备注

在下面的 Azure CLI 代码中,date 参数 -d 在 macOS 中是无效参数。In the below Azure CLI code, date parameter -d is an invalid argument in macOS. 因此,macOS 用户若要在 macOS 的终端中将当前时间增加 2 小时,则应使用 -v+2HSo macOS users, to add 2 hours to current time in terminal on macOS you should use -v+2H.


$projectName = Read-Host -Prompt "Enter a project name:"   # This name is used to generate names for Azure resources, such as storage account name.
$templateFile = Read-Host -Prompt "Enter the main template file and path"

$resourceGroupName="${projectName}rg"
$storageAccountName="${projectName}store"
$containerName = "templates"
$fileName = "linkedStorageAccount.json" # A file name used for downloading and uploading the linked template.

$key = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName).Value[0]
$context = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $key

# Generate a SAS token
$linkedTemplateUri = New-AzStorageBlobSASToken `
    -Context $context `
    -Container $containerName `
    -Blob $fileName `
    -Permission r `
    -ExpiryTime (Get-Date).AddHours(2.0) `
    -FullUri

# Deploy the template
New-AzResourceGroupDeployment `
  -Name DeployLinkedTemplate `
  -ResourceGroupName $resourceGroupName `
  -TemplateFile $templateFile `
  -projectName $projectName `
  -linkedTemplateUri $linkedTemplateUri `
  -verbose

清理资源Clean up resources

通过删除资源组来清理你部署的资源。Clean up the resources you deployed by deleting the resource group.

  1. 在 Azure 门户上的左侧菜单中选择“资源组”。From the Azure portal, select Resource group from the left menu.
  2. 在“按名称筛选”字段中输入资源组名称。Enter the resource group name in the Filter by name field.
  3. 选择资源组名称。Select the resource group name.
  4. 在顶部菜单中选择“删除资源组”。Select Delete resource group from the top menu.

后续步骤Next steps

现在,你已了解如何部署链接模板。You learned how to deploy a linked template. 下一篇教程将介绍如何创建用于部署模板的 DevOps 管道。In the next tutorial, you learn how to create a DevOps pipeline to deploy a template.