练习 - 将部署脚本添加到 ARM 模板

已完成

重要

需要自己的 Azure 订阅才能运行此练习,这可能会产生费用。 如果还没有 Azure 订阅,请在开始前创建一个免费帐户

在团队部署应用程序的过程中,你需要创建一个存储帐户,并在 Blob 存储中暂存一个文件,以便应用程序读取。 到目前为止,每次设置新环境时,你都是手动复制文件。 你决定在环境创建过程中,使用部署脚本来自动执行此步骤。

在此练习中,你将使用现有的 Azure 资源管理器 (ARM) 模板并添加新的部署脚本。

在此过程中,你将:

  • 创建起始模板。
  • 添加部署脚本的先决条件,其中包括用户分配的托管标识和角色分配。
  • 添加部署脚本。
  • 部署模板,并验证结果。

本练习使用适用于 Visual Studio Code 的 Azure 资源管理器工具。 请务必在 Visual Studio Code 中安装此扩展。

本练习使用适用于 Visual Studio Code 的 Bicep 扩展。 请务必在 Visual Studio Code 中安装此扩展。

创建共享模板

你从团队一直在使用的现有模板着手。 此模板将创建存储帐户,设置 Blob 服务并要求 HTTPS,以及为配置文件创建 Blob 容器。

  1. 打开 Visual Studio Code。

  2. 新建一个名为 azuredeploy.json 的文件。

  3. 保存空文件,以便 Visual Studio Code 加载 ARM 模板工具。

    你可以选择“文件”>“另存为”,也可以在 Windows 中选择Ctrl+S(在 macOS 上选择 ⌘+S)。 请务必记住保存文件的位置。 例如,你可能希望创建脚本文件,并将其存储在其中。

  4. 将以下起始模板复制到 azuredeploy.json 中。

    {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.1",
        "apiProfile": "",
        "parameters": {},
        "variables": {
            "storageAccountName": "[concat('storage', uniqueString(resourceGroup().id))]",
            "storageBlobContainerName": "config"
        },
        "functions": [],
        "resources": [
            {
                "name": "[variables('storageAccountName')]",
                "type": "Microsoft.Storage/storageAccounts",
                "apiVersion": "2023-01-01",
                "tags": {
                    "displayName": "[variables('storageAccountName')]"
                },
                "location": "[resourceGroup().location]",
                "kind": "StorageV2",
                "sku": {
                    "name": "Standard_LRS",
                    "tier": "Standard"
                },
                "properties": {
                    "allowBlobPublicAccess": true,
                    "encryption": {
                        "services": {
                            "blob": {
                                "enabled": true
                            }
                        },
                        "keySource": "Microsoft.Storage"
                    },
                    "supportsHttpsTrafficOnly": true
                }
            },
            {
                "type": "Microsoft.Storage/storageAccounts/blobServices",
                "apiVersion": "2019-04-01",
                "name": "[concat(variables('storageAccountName'), '/default')]",
                "dependsOn": [
                    "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                ]
            },
            {
                "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
                "apiVersion": "2019-04-01",
                "name": "[concat(variables('storageAccountName'),'/default/',variables('storageBlobContainerName'))]",
                "dependsOn": [
                    "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
                    "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                ],
                "properties": {
                    "publicAccess": "Blob"
                }
            }
        ]
    }
    
  5. 保存模板。

  1. 打开 Visual Studio Code。

  2. 新建一个名为 main.bicep 的文件。

  3. 保存空文件,以便 Visual Studio Code 加载 Bicep 工具。

    你可以选择“文件”>“另存为”,也可以在 Windows 中选择Ctrl+S(在 macOS 上选择 ⌘+S)。 请务必记住保存文件的位置。 例如,你可能希望创建脚本文件,并将其存储在其中。

  4. 将以下起始模板复制到 main.bicep 中。

    var storageAccountName = 'storage${uniqueString(resourceGroup().id)}'
    var storageBlobContainerName = 'config'
    
    resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
      name: storageAccountName
      tags: {
        displayName: storageAccountName
      }
      location: resourceGroup().location
      kind: 'StorageV2'
      sku: {
        name: 'Standard_LRS'
        tier: 'Standard'
      }
      properties: {
        allowBlobPublicAccess: true
        encryption: {
          services: {
            blob: {
              enabled: true
            }
          }
          keySource: 'Microsoft.Storage'
        }
        supportsHttpsTrafficOnly: true
      }
    
      resource blobService 'blobServices' existing = {
        name: 'default'
      }
    }
    
    resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-04-01' = {
      parent: storageAccount::blobService
      name: storageBlobContainerName
      properties: {
        publicAccess: 'Blob'
      }
    }
    
  5. 保存模板。

添加用户分配的托管标识

接下来,需要创建用户分配的托管标识。 使用基础结构即代码方法,你可以在模板中创建标识。

  1. 编辑 azuredeploy.json 的 variables 部分,以包括:

    "userAssignedIdentityName": "configDeployer",
    
  2. 编辑 azuredeploy.json 的 resources 部分,以包括:

    {
        "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
        "apiVersion": "2018-11-30",
        "name": "[variables('userAssignedIdentityName')]",
        "location": "[resourceGroup().location]"
    }
    
  3. 保存模板。

  1. 在 main.bicep 中的变量定义下,添加:

    var userAssignedIdentityName = 'configDeployer'
    
  2. 在资源定义下,添加:

    resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
      name: userAssignedIdentityName
      location: resourceGroup().location
    }
    
  3. 保存模板。

设置托管标识的参与者角色

定义托管标识后,可以为其分配具有资源组权限的角色。 你将为其分配参与者角色。 可通过角色定义 ID(即 GUID)来标识角色。 参与者角色内置于 Azure 中,因而记录了其角色定义 ID。

分配角色还需要 GUID 名称。 可以使用 guid 函数创建资源组和角色名称唯一的 GUID。

  1. 编辑 azuredeploy.json 的 variables 部分,以包括:

    "roleAssignmentName": "[guid(concat(resourceGroup().id, 'contributor'))]",
    "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
    
  2. 编辑 azuredeploy.json 的 resources 部分,以包括:

    {
        "type": "Microsoft.Authorization/roleAssignments",
        "apiVersion": "2020-04-01-preview",
        "name": "[variables('roleAssignmentName')]",
        "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName'))]" ],
        "properties": {
            "roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
            "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName')), '2015-08-31-preview').principalId]",
            "scope": "[resourceGroup().id]",
            "principalType": "ServicePrincipal"
        }
    }
    
  3. 保存模板。

  1. 在 main.bicep 中的变量定义下,添加:

    var roleAssignmentName = guid(resourceGroup().id, 'contributor')
    var contributorRoleDefinitionId = resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
    
  2. 在资源定义下,添加:

    resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
      name: roleAssignmentName
      properties: {
        roleDefinitionId: contributorRoleDefinitionId
        principalId: userAssignedIdentity.properties.principalId
        principalType: 'ServicePrincipal'
      }
    }
    
  3. 保存模板。

创建部署脚本

现在,你已具备部署脚本的所有先决条件。 将从部署脚本所需的公用值开始。 存在两个依赖项:角色分配和 Blob 存储容器。 具有这两个依赖项后,脚本才能运行。

  1. 编辑 azuredeploy.json 的 variables 部分,以包括:

    "deploymentScriptName": "CopyConfigScript"
    
  2. 编辑 azuredeploy.json 的 resources 部分,以包括:

    {
        "type": "Microsoft.Resources/deploymentScripts",
        "apiVersion": "2020-10-01",
        "name": "[variables('deploymentScriptName')]",
        "location": "[resourceGroup().location]",
        "kind": "AzurePowerShell",
        "dependsOn": [
            "[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentName'))]",
            "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageAccountName'), 'default', variables('storageBlobContainerName'))]"
        ],
        "identity": {
            "type": "UserAssigned",
            "userAssignedIdentities": {
                "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',variables('userAssignedIdentityName'))]": {}
            }
        }
    }
    
  3. 向资源添加 properties 部分,以定义脚本和所需的其他值。

    "properties": {
        "azPowerShellVersion": "3.0",
        "scriptContent": "
            Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
            $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
            $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $StorageAccount.Context
            $DeploymentScriptOutputs = @{}
            $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
            $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
        ",
        "retentionInterval": "P1D"
    }
    
  4. 保存模板。

  1. 在 main.bicep 中的变量定义下,添加:

    var deploymentScriptName = 'CopyConfigScript'
    
  2. 在资源定义下,添加:

    resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
      name: deploymentScriptName
      location: resourceGroup().location
      kind: 'AzurePowerShell'
      identity: {
        type: 'UserAssigned'
        userAssignedIdentities: {
          '${userAssignedIdentity.id}': {}
        }
      }
      dependsOn: [
        roleAssignment
        blobContainer
      ]
    }
    
  3. 向资源添加 properties 部分,以定义脚本和所需的其他值。

    properties: {
      azPowerShellVersion: '3.0'
      scriptContent: '''
        Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
        $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
        $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $storageAccount.Context
        $DeploymentScriptOutputs = @{}
        $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
        $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
      '''
      retentionInterval: 'P1D'
    }
    
  4. 保存模板。

添加模板输出

现在,你已具有可将文件上传到 Azure Blob 存储的部署脚本,你可能会需要在之后的自动化过程中引用该文件位置。 (也许可运行测试来验证该文件是否在你认为应该在的位置。)

在 ARM 模板的 resources 部分之后,添加一个输出,该输出引用部署脚本所报告的文件的 URI。

"outputs": {
    "fileUri": {
        "type": "string",
        "value": "[reference(variables('deploymentScriptName')).outputs.Uri]"
    }
}

在文件底部资源定义的后面,添加一个输出,该输出引用部署脚本所报告的文件的 URI。

output fileUri string = deploymentScript.properties.outputs.Uri

验证模板

模板应如下所示:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.1",
    "apiProfile": "",
    "parameters": {},
    "variables": {
        "storageAccountName": "[concat('storage', uniqueString(resourceGroup().id))]",
        "storageBlobContainerName": "config",
        "userAssignedIdentityName": "configDeployer",
        "roleAssignmentName": "[guid(concat(resourceGroup().id, 'contributor'))]",
        "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
        "deploymentScriptName": "CopyConfigScript"
    },
    "functions": [],
    "resources": [
        {
            "name": "[variables('storageAccountName')]",
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2023-01-01",
            "tags": {
                "displayName": "[variables('storageAccountName')]"
            },
            "location": "[resourceGroup().location]",
            "kind": "StorageV2",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "properties": {
                "allowBlobPublicAccess": true,
                "encryption": {
                    "services": {
                        "blob": {
                            "enabled": true
                        }
                    },
                    "keySource": "Microsoft.Storage"
                },
                "supportsHttpsTrafficOnly": true
            }
        },
        {
            "type": "Microsoft.Storage/storageAccounts/blobServices",
            "apiVersion": "2019-04-01",
            "name": "[concat(variables('storageAccountName'), '/default')]",
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
            ]
        },
        {
            "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
            "apiVersion": "2019-04-01",
            "name": "[concat(variables('storageAccountName'),'/default/',variables('storageBlobContainerName'))]",
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
                "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
            ],
            "properties": {
                "publicAccess": "Blob"
            }
        },
        {
            "type": "Microsoft.ManagedIdentity/userAssignedIdentities",
            "apiVersion": "2018-11-30",
            "name": "[variables('userAssignedIdentityName')]",
            "location": "[resourceGroup().location]"
        },
        {
            "type": "Microsoft.Authorization/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[variables('roleAssignmentName')]",
            "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName'))]" ],
            "properties": {
                "roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
                "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('userAssignedIdentityName')), '2015-08-31-preview').principalId]",
                "scope": "[resourceGroup().id]",
                "principalType": "ServicePrincipal"
            }
        },
        {
            "type": "Microsoft.Resources/deploymentScripts",
            "apiVersion": "2020-10-01",
            "name": "[variables('deploymentScriptName')]",
            "location": "[resourceGroup().location]",
            "kind": "AzurePowerShell",
            "dependsOn": [
                "[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentName'))]",
                "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageAccountName'), 'default', variables('storageBlobContainerName'))]"
            ],
            "identity": {
                "type": "UserAssigned",
                "userAssignedIdentities": {
                    "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',variables('userAssignedIdentityName'))]": {}
                }
            },
            "properties": {
                "azPowerShellVersion": "3.0",
                "scriptContent": "
                    Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
                    $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
                    $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $StorageAccount.Context
                    $DeploymentScriptOutputs = @{}
                    $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
                    $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
                ",
                "retentionInterval": "P1D"
            }
        }
    ],
    "outputs": {
        "fileUri": {
            "type": "string",
            "value": "[reference(variables('deploymentScriptName')).outputs.Uri]"
        }
    }
}
var storageAccountName = 'storage${uniqueString(resourceGroup().id)}'
var storageBlobContainerName = 'config'
var userAssignedIdentityName = 'configDeployer'
var roleAssignmentName = guid(resourceGroup().id, 'contributor')
var contributorRoleDefinitionId = resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
var deploymentScriptName = 'CopyConfigScript'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  tags: {
    displayName: storageAccountName
  }
  location: resourceGroup().location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
    tier: 'Standard'
  }
  properties: {
    allowBlobPublicAccess: true
    encryption: {
      services: {
        blob: {
          enabled: true
        }
      }
      keySource: 'Microsoft.Storage'
    }
    supportsHttpsTrafficOnly: true
  }

  resource blobService 'blobServices' existing = {
    name: 'default'
  }
}

resource blobContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-04-01' = {
  parent: storageAccount::blobService
  name: storageBlobContainerName
  properties: {
    publicAccess: 'Blob'
  }
}

resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: userAssignedIdentityName
  location: resourceGroup().location
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: roleAssignmentName
  properties: {
    roleDefinitionId: contributorRoleDefinitionId
    principalId: userAssignedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
  name: deploymentScriptName
  location: resourceGroup().location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${userAssignedIdentity.id}': {}
    }
  }
  properties: {
    azPowerShellVersion: '3.0'
    scriptContent: '''
      Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/mslearn-arm-deploymentscripts-sample/appsettings.json' -OutFile 'appsettings.json'
      $storageAccount = Get-AzStorageAccount -ResourceGroupName 'learndeploymentscript_exercise_1' | Where-Object { $_.StorageAccountName -like 'storage*' }
      $blob = Set-AzStorageBlobContent -File 'appsettings.json' -Container 'config' -Blob 'appsettings.json' -Context $storageAccount.Context
      $DeploymentScriptOutputs = @{}
      $DeploymentScriptOutputs['Uri'] = $blob.ICloudBlob.Uri
      $DeploymentScriptOutputs['StorageUri'] = $blob.ICloudBlob.StorageUri
    '''
    retentionInterval: 'P1D'
  }
  dependsOn: [
    roleAssignment
    blobContainer
  ]
}

output fileUri string = deploymentScript.properties.outputs.Uri

如果不是,请复制示例或调整模板以与该示例一致。

部署模板

若要将此模板部署到 Azure,你需要从 Visual Studio Code 终端登录到 Azure 帐户。 请确保已安装 Azure CLI 工具。

  1. 在“终端”菜单中,选择“新终端”。 终端窗口通常在屏幕的下半部分打开。

  2. 如果终端窗口右侧显示的 shell 为“bash”,则将打开正确的 shell,你可以跳到下一部分。

    Visual Studio Code 终端窗口的屏幕截图,其中显示了 bash 选项。

  3. 如果出现“bash”以外的 shell,请选择 shell 下拉箭头,然后选择“Azure Cloud Shell (Bash)”

    Visual Studio Code 终端窗口的屏幕截图,其中显示了终端 shell 下拉列表并选中了“Git Bash (默认)”。

  4. 在终端 shell 列表中,选择“bash”。

    Visual Studio Code 终端窗口的屏幕截图,其中选中了 bash 终端。

  5. 在终端中,转到保存模板的目录。 例如,如果将模板保存到 templates 文件夹,则可以使用以下命令:

    cd templates
    

使用 Azure CLI 登录到 Azure

  1. 在 Visual Studio Code 终端中,运行以下命令登录到 Azure:

    az login
    
  2. 在打开的浏览器中,登录到 Azure 帐户。

    Visual Studio Code 终端显示与此帐户关联的订阅列表。

  3. 在列表中,找到要用于本次练习的订阅。

    如果你在登录时错过了列表,则可以使用以下代码片段再次列出订阅。

    az account list --output table
    
  4. 为在此会话中运行的所有 Azure CLI 命令设置默认订阅。

    az account set --subscription "Your Subscription Name or ID"
    

若要将此模板部署到 Azure,你需要从 Visual Studio Code 终端登录到 Azure 帐户。 请确保已安装 Azure CLI 工具。

  1. 在“终端”菜单中,选择“新终端”。 终端窗口通常在屏幕的下半部分打开。

  2. 如果终端窗口右侧显示的 shell 为“bash”,则将打开正确的 shell,你可以跳到下一部分。

    Visual Studio Code 终端窗口的屏幕截图,其中显示了 bash 选项。

  3. 如果出现“bash”以外的 shell,请选择 shell 下拉箭头,然后选择“Azure Cloud Shell (Bash)”

    Visual Studio Code 终端窗口的屏幕截图,其中显示了终端 shell 下拉列表并选中了“Git Bash (默认)”。

  4. 在终端 shell 列表中,选择“bash”。

    Visual Studio Code 终端窗口的屏幕截图,其中选中了 bash 终端。

  5. 在终端中,转到保存模板的目录。 例如,如果将模板保存到 templates 文件夹,则可以使用以下命令:

    cd templates
    

安装 Bicep

运行以下命令以确保具有最新版本的 Bicep:

az bicep install && az bicep upgrade

使用 Azure CLI 登录到 Azure

  1. 在 Visual Studio Code 终端中,运行以下命令登录到 Azure:

    az login
    
  2. 在打开的浏览器中,登录到 Azure 帐户。

    Visual Studio Code 终端显示与此帐户关联的订阅列表。

  3. 在列表中,找到要用于本次练习的订阅。

    如果你在登录时错过了列表,则可以使用以下代码片段再次列出订阅。

    az account list --output table
    
  4. 为在此会话中运行的所有 Azure CLI 命令设置默认订阅。

    az account set --subscription "Your Subscription Name or ID"
    

若要将此模板部署到 Azure,需要从 Visual Studio Code 终端登录到 Azure 帐户。 请确保已安装 Azure PowerShell,并且登录的帐户与激活了沙盒的帐户相同。

  1. 在“终端”菜单中,选择“新终端”。 终端窗口通常在屏幕的下半部分打开。

  2. 如果终端窗口右侧显示的 shell 为“powershell”或“pwsh”,则会打开正确的 shell,你可以跳到下一部分。

    Visual Studio Code 终端窗口的屏幕截图,其中在 shell 下拉列表中显示了 pwsh 选项。

  3. 如果出现“powershell”或“pwsh”以外的 shell,请选择 shell 下拉箭头,然后选择“PowerShell”

    Visual Studio Code 终端窗口的屏幕截图,其中显示了终端 shell 下拉列表并选中了 PowerShell。

  4. 在终端 shell 列表中,选择“powershell”或“pwsh”。

    Visual Studio Code 终端窗口的屏幕截图,其中选择了 PowerShell 终端。

  5. 在终端中,转到保存模板的目录。 例如,如果将模板保存到 templates 文件夹,则可以使用以下命令:

    Set-Location -Path templates
    

使用 Azure PowerShell 登录到 Azure

  1. 在 Visual Studio Code 终端中,运行以下命令登录到 Azure:

    Connect-AzAccount
    
  2. 在打开的浏览器中,登录到 Azure 帐户。

  3. 通过运行以下命令获取要用于此练习的订阅的 ID:

    Get-AzSubscription
    

    订阅 ID 位于第二列。 复制第二列。 它类似于 aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e

  4. 为在此会话中运行的所有 Azure PowerShell 命令设置默认订阅。

    Set-AzContext -SubscriptionId {Your subscription ID}
    

若要将此模板部署到 Azure,需要从 Visual Studio Code 终端登录到 Azure 帐户。 确保已安装 Azure PowerShell

  1. 在“终端”菜单中,选择“新终端”。 终端窗口通常在屏幕的下半部分打开。

  2. 如果终端窗口右侧显示的 shell 为“powershell”或“pwsh”,则会打开正确的 shell,你可以跳到下一部分。

    Visual Studio Code 终端窗口的屏幕截图,其中在 shell 下拉列表中显示了 pwsh 选项。

  3. 如果出现“powershell”或“pwsh”以外的 shell,请选择 shell 下拉箭头,然后选择“PowerShell”

    Visual Studio Code 终端窗口的屏幕截图,其中显示了终端 shell 下拉列表并选中了 PowerShell。

  4. 在终端 shell 列表中,选择“powershell”或“pwsh”。

    Visual Studio Code 终端窗口的屏幕截图,其中选择了 PowerShell 终端。

  5. 在终端中,转到保存模板的目录。 例如,如果将模板保存到 templates 文件夹,则可以使用以下命令:

    Set-Location -Path templates
    

安装 Bicep CLI

若要从 Azure PowerShell 中使用 Bicep,请安装 Bicep CLI

使用 Azure PowerShell 登录到 Azure

  1. 在 Visual Studio Code 终端中,运行以下命令登录到 Azure:

    Connect-AzAccount
    
  2. 在打开的浏览器中,登录到 Azure 帐户。

  3. 通过运行以下命令获取要用于此练习的订阅的 ID:

    Get-AzSubscription
    

    订阅 ID 位于第二列。 复制第二列。 它类似于 aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e

  4. 为在此会话中运行的所有 Azure PowerShell 命令设置默认订阅。

    Set-AzContext -SubscriptionId {Your subscription ID}
    

接下来,需要创建一个资源组,以包含将在此练习中创建的资源。 通过使用新的资源组,你可在练习后更轻松地进行清理。

在 Visual Studio Code 的终端中运行以下命令,为此练习创建资源组:

为练习创建资源组

resourceGroupName="learndeploymentscript_exercise_1"
az group create --location eastus --name $resourceGroupName
$resourceGroupName = 'learndeploymentscript_exercise_1'
New-AzResourceGroup -Location eastus -Name $resourceGroupName

注意

如果对资源组使用不同的名称,则需要确保更新该脚本。 稍后在此模块中,你将了解如何在脚本中避免对资源组名称进行硬编码。

将模板部署到 Azure

以下代码将 ARM 模板部署到 Azure。 你会看到成功的部署。

在 Visual Studio Code 终端中使用 Azure CLI 命令部署模板。

templateFile="azuredeploy.json"
today=$(date +"%d-%b-%Y")
deploymentName="deploymentscript-"$today

az deployment group create \
    --resource-group $resourceGroupName \
    --name $deploymentName \
    --template-file $templateFile

以下代码将 ARM 模板部署到 Azure。 你会看到成功的部署。

在 Visual Studio Code 终端中使用 Azure CLI 命令部署模板。

templateFile="main.bicep"
today=$(date +"%d-%b-%Y")
deploymentName="deploymentscript-"$today

az deployment group create \
    --resource-group $resourceGroupName \
    --name $deploymentName \
    --template-file $templateFile

以下代码将模板部署到 Azure。 你会看到成功的部署。

在终端中使用 Azure PowerShell 命令部署模板。

$templateFile = 'azuredeploy.json'
$today = Get-Date -Format 'MM-dd-yyyy'
$deploymentName = "deploymentscript-$today"
New-AzResourceGroupDeployment `
  -ResourceGroupName $resourceGroupName `
  -Name $deploymentName `
  -TemplateFile $templateFile

以下代码将模板部署到 Azure。 你会看到成功的部署。

在终端中使用 Azure PowerShell 命令部署模板。

$templateFile = 'main.bicep'
$today = Get-Date -Format 'MM-dd-yyyy'
$deploymentName = "deploymentscript-$today"
New-AzResourceGroupDeployment `
  -ResourceGroupName $resourceGroupName `
  -Name $deploymentName `
  -TemplateFile $templateFile

查看模板结果

部署完成后,将向你提供一个 URL,该 URL 指向部署脚本复制到 Blob 存储中的文件。

  1. 使用模板部署中的 URL 输出来检索该文件,以确认部署脚本正常运作。

    uri=$(az deployment group show --resource-group $resourceGroupName --name $deploymentName --query 'properties.outputs.fileUri.value' --output tsv)
    curl $uri
    

    命令返回以下代码。

    {
      "environment": "production",
      "hostname": "tailwindtraders.com",
      "Logging": {
        "LogLevel": {
          "Default": "Debug"
        }
      },
      "ApplicationInsights": {
        "InstrumentationKey": ""
      },
      "AllowedHosts": "*",
      "CosmosDb": {
        "Host": "",
        "Key": "",
        "Database": "Products"
      }
    }
    
  2. 还可以从 Azure 门户或使用以下命令查看日志(以及有关部署的其他详细信息)。

    az deployment-scripts show-log --resource-group $resourceGroupName --name CopyConfigScript
    
  1. 使用模板部署中的 URL 输出来检索该文件,以确认部署脚本正常运作。

    $fileUri = (Get-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName).Outputs.fileUri.Value
    Invoke-RestMethod $fileUri
    

    命令返回以下代码。

    environment         : production
    hostname            : tailwindtraders.com
    Logging             : @{LogLevel=}
    ApplicationInsights : @{InstrumentationKey=}
    AllowedHosts        : *
    CosmosDb            : @{Host=; Key=; Database=Products}
    
  2. 还可以从 Azure 门户或使用以下命令行查看日志(以及有关部署的其他详细信息)。

    Get-AzDeploymentScriptLog -ResourceGroupName $resourceGroupName -Name CopyConfigScript
    

清理资源组

使用部署脚本成功部署 ARM 模板后,可以删除包含已创建的所有资源和角色分配的资源组。

az group delete --name $resourceGroupName
Remove-AzResourceGroup -Name $resourceGroupName