快速入門:使用 Bicep 建立 Windows 虛擬機器擴展集

虛擬機器擴展集可讓您部署和管理一組自動調整的虛擬機器。 您可以手動調整虛擬機器擴展集中的 VM 數目,或定義規則以根據 CPU、記憶體需求或網路流量這類資源使用量進行自動調整。 其後,Azure 負載平衡器會將流量散發至虛擬機器擴展集中的 VM 執行個體。 在此快速入門中,您會使用 Bicep 建立虛擬機器擴展集,並部署範例應用程式。

Bicep 是使用宣告式語法來部署 Azure 資源的特定領域語言 (DSL)。 其提供簡潔的語法、可靠的類型安全,並支援程式碼重複使用。 Bicep 能夠為您在 Azure 中的基礎結構即程式碼解決方案,提供最佳的製作體驗。

必要條件

如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

檢閱 Bicep 檔案

此快速入門中使用的 Bicep 檔案是來自 Azure 快速入門範本

@description('String used as a base for naming resources. Must be 3-61 characters in length and globally unique across Azure. A hash is prepended to this string for some resources, and resource-specific information is appended.')
@minLength(3)
@maxLength(61)
param vmssName string

@description('Size of VMs in the VM Scale Set.')
param vmSku string = 'Standard_D2s_v3'

@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version. Allowed values: 2008-R2-SP1, 2012-Datacenter, 2012-R2-Datacenter & 2016-Datacenter, 2019-Datacenter.')
@allowed([
  '2019-DataCenter-GenSecond'
  '2016-DataCenter-GenSecond'
  '2022-datacenter-azure-edition'
])
param windowsOSVersion string = '2022-datacenter-azure-edition'

@description('Security Type of the Virtual Machine.')
@allowed([
  'Standard'
  'TrustedLaunch'
])
param securityType string = 'TrustedLaunch'

@description('Number of VM instances (100 or less).')
@minValue(1)
@maxValue(100)
param instanceCount int = 3

@description('When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true.')
param singlePlacementGroup bool = true

@description('Admin username on all VMs.')
param adminUsername string = 'vmssadmin'

@description('Admin password on all VMs.')
@secure()
param adminPassword string

@description('The base URI where artifacts required by this template are located. For example, if stored on a public GitHub repo, you\'d use the following URI: https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vmss-windows-webapp-dsc-autoscale/.')
param _artifactsLocation string = deployment().properties.templateLink.uri

@description('The sasToken required to access _artifactsLocation.  If your artifacts are stored on a public repo or public storage account you can leave this blank.')
@secure()
param _artifactsLocationSasToken string = ''

@description('Location of the PowerShell DSC zip file relative to the URI specified in the _artifactsLocation, i.e. DSC/IISInstall.ps1.zip')
param powershelldscZip string = 'DSC/InstallIIS.zip'

@description('Location of the  of the WebDeploy package zip file relative to the URI specified in _artifactsLocation, i.e. WebDeploy/DefaultASPWebApp.v1.0.zip')
param webDeployPackage string = 'WebDeploy/DefaultASPWebApp.v1.0.zip'

@description('Version number of the DSC deployment. Changing this value on subsequent deployments will trigger the extension to run.')
param powershelldscUpdateTagVersion string = '1.0'

@description('Location for all resources.')
param location string = resourceGroup().location

@description('Fault Domain count for each placement group.')
param platformFaultDomainCount int = 1

var vmScaleSetName = toLower(substring('vmssName${uniqueString(resourceGroup().id)}', 0, 9))
var longvmScaleSet = toLower(vmssName)
var addressPrefix = '10.0.0.0/16'
var subnetPrefix = '10.0.0.0/24'
var vNetName = '${vmScaleSetName}vnet'
var publicIPAddressName = '${vmScaleSetName}pip'
var subnetName = '${vmScaleSetName}subnet'
var loadBalancerName = '${vmScaleSetName}lb'
var publicIPAddressID = publicIPAddress.id
var lbProbeID = resourceId('Microsoft.Network/loadBalancers/probes', loadBalancerName, 'tcpProbe')
var natPoolName = '${vmScaleSetName}natpool'
var bePoolName = '${vmScaleSetName}bepool'
var lbPoolID = resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadBalancerName, bePoolName)
var natStartPort = 50000
var natEndPort = 50119
var natBackendPort = 3389
var nicName = '${vmScaleSetName}nic'
var ipConfigName = '${vmScaleSetName}ipconfig'
var frontEndIPConfigID = resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', loadBalancerName, 'loadBalancerFrontEnd')
var osType = {
  publisher: 'MicrosoftWindowsServer'
  offer: 'WindowsServer'
  sku: windowsOSVersion
  version: 'latest'
}
var securityProfileJson = {
  uefiSettings: {
    secureBootEnabled: true
    vTpmEnabled: true
  }
  securityType: securityType
}
var imageReference = osType
var webDeployPackageFullPath = uri(_artifactsLocation, '${webDeployPackage}${_artifactsLocationSasToken}')
var powershelldscZipFullPath = uri(_artifactsLocation, '${powershelldscZip}${_artifactsLocationSasToken}')

resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = {
  name: loadBalancerName
  location: location
  properties: {
    frontendIPConfigurations: [
      {
        name: 'LoadBalancerFrontEnd'
        properties: {
          publicIPAddress: {
            id: publicIPAddressID
          }
        }
      }
    ]
    backendAddressPools: [
      {
        name: bePoolName
      }
    ]
    inboundNatPools: [
      {
        name: natPoolName
        properties: {
          frontendIPConfiguration: {
            id: frontEndIPConfigID
          }
          protocol: 'Tcp'
          frontendPortRangeStart: natStartPort
          frontendPortRangeEnd: natEndPort
          backendPort: natBackendPort
        }
      }
    ]
    loadBalancingRules: [
      {
        name: 'LBRule'
        properties: {
          frontendIPConfiguration: {
            id: frontEndIPConfigID
          }
          backendAddressPool: {
            id: lbPoolID
          }
          protocol: 'Tcp'
          frontendPort: 80
          backendPort: 80
          enableFloatingIP: false
          idleTimeoutInMinutes: 5
          probe: {
            id: lbProbeID
          }
        }
      }
    ]
    probes: [
      {
        name: 'tcpProbe'
        properties: {
          protocol: 'Tcp'
          port: 80
          intervalInSeconds: 5
          numberOfProbes: 2
        }
      }
    ]
  }
}

resource vmScaleSet 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = {
  name: vmScaleSetName
  location: location
  sku: {
    name: vmSku
    tier: 'Standard'
    capacity: instanceCount
  }
  properties: {
    overprovision: true
    upgradePolicy: {
      mode: 'Automatic'
    }
    singlePlacementGroup: singlePlacementGroup
    platformFaultDomainCount: platformFaultDomainCount
    virtualMachineProfile: {
      storageProfile: {
        osDisk: {
          caching: 'ReadWrite'
          createOption: 'FromImage'
        }
        imageReference: imageReference
      }
      osProfile: {
        computerNamePrefix: vmScaleSetName
        adminUsername: adminUsername
        adminPassword: adminPassword
      }
      securityProfile: ((securityType == 'TrustedLaunch') ? securityProfileJson : null)
      networkProfile: {
        networkInterfaceConfigurations: [
          {
            name: nicName
            properties: {
              primary: true
              ipConfigurations: [
                {
                  name: ipConfigName
                  properties: {
                    subnet: {
                      id: vNet.properties.subnets[0].id
                    }
                    loadBalancerBackendAddressPools: [
                      {
                        id: lbPoolID
                      }
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
      extensionProfile: {
        extensions: [
          {
            name: 'Microsoft.Powershell.DSC'
            properties: {
              publisher: 'Microsoft.Powershell'
              type: 'DSC'
              typeHandlerVersion: '2.9'
              autoUpgradeMinorVersion: true
              forceUpdateTag: powershelldscUpdateTagVersion
              settings: {
                configuration: {
                  url: powershelldscZipFullPath
                  script: 'InstallIIS.ps1'
                  function: 'InstallIIS'
                }
                configurationArguments: {
                  nodeName: 'localhost'
                  WebDeployPackagePath: webDeployPackageFullPath
                }
              }
            }
          }
        ]
      }
    }
  }
}

resource publicIPAddress 'Microsoft.Network/publicIPAddresses@2023-04-01' = {
  name: publicIPAddressName
  location: location
  properties: {
    publicIPAllocationMethod: 'Static'
    dnsSettings: {
      domainNameLabel: longvmScaleSet
    }
  }
}

resource vNet 'Microsoft.Network/virtualNetworks@2023-04-01' = {
  name: vNetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressPrefix
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: subnetPrefix
        }
      }
    ]
  }
}

resource autoscalehost 'Microsoft.Insights/autoscalesettings@2022-10-01' = {
  name: 'autoscalehost'
  location: location
  properties: {
    name: 'autoscalehost'
    targetResourceUri: vmScaleSet.id
    enabled: true
    profiles: [
      {
        name: 'Profile1'
        capacity: {
          minimum: '1'
          maximum: '10'
          default: '1'
        }
        rules: [
          {
            metricTrigger: {
              metricName: 'Percentage CPU'
              metricResourceUri: vmScaleSet.id
              timeGrain: 'PT1M'
              statistic: 'Average'
              timeWindow: 'PT5M'
              timeAggregation: 'Average'
              operator: 'GreaterThan'
              threshold: 50
            }
            scaleAction: {
              direction: 'Increase'
              type: 'ChangeCount'
              value: '1'
              cooldown: 'PT5M'
            }
          }
          {
            metricTrigger: {
              metricName: 'Percentage CPU'
              metricResourceUri: vmScaleSet.id
              timeGrain: 'PT1M'
              statistic: 'Average'
              timeWindow: 'PT5M'
              timeAggregation: 'Average'
              operator: 'LessThan'
              threshold: 30
            }
            scaleAction: {
              direction: 'Decrease'
              type: 'ChangeCount'
              value: '1'
              cooldown: 'PT5M'
            }
          }
        ]
      }
    ]
  }
}

output applicationUrl string = uri('http://${publicIPAddress.properties.dnsSettings.fqdn}', '/MyApp')

Bicep 檔案中會定義下列資源:

定義擴展集

若要使用 Bicep 檔案建立虛擬機器擴展集,您必須定義適當的資源。 虛擬機器擴展集資源類型的核心部分是:

屬性 屬性描述 範例範本值
type 要建立的 Azure 資源類型 Microsoft.Compute/virtualMachineScaleSets
NAME 擴展集名稱 myScaleSet
location 要建立擴展集的位置 美國東部
sku.name 每個擴展集執行個體的 VM 大小 標準_A1
sku.capacity 最初要建立的 VM 執行個體數目 2
upgradePolicy.mode 發生變更時的 VM 執行個體升級模式 自動
imageReference 要用於 VM 執行個體的平台或自訂映像 Microsoft Windows Server 2016 資料中心
osProfile.computerNamePrefix 每個 VM 執行個體的名稱前置詞 myvmss
osProfile.adminUsername 每個 VM 執行個體的使用者名稱 azureuser
osProfile.adminPassword 每個 VM 執行個體的密碼 P@ssw0rd!

若要自訂虛擬機器擴展集 Bicep 檔案,您可以變更 VM 大小或初始容量。 或使用不同的平台或自訂映像。

新增範例應用程式

若要測試您的虛擬機器擴展集,請安裝基本 Web 應用程式。 當您部署虛擬機器擴展集時,VM 延伸模組可以提供部署後設定和自動化工作,例如安裝應用程式。 您可以從 GitHub 下載指令碼,或是在延伸模組執行階段將指令碼提供給 Azure 入口網站。 若要將延伸模組套用至虛擬機器擴展集,請將 extensionProfile 區段新增至上述資源範例。 延伸模組設定檔通常會定義下列屬性:

  • 擴充功能類型
  • 延伸模組發行者
  • 延伸模組版本
  • 設定或安裝指令碼的位置
  • 在 VM 執行個體上執行的命令

Bicep 檔案會使用 PowerShell DSC 延伸模組來安裝 IIS 中所執行的 ASP.NET MVC 應用程式。

安裝指令碼會從 GitHub 進行下載,如 url 中所定義。 然後,延伸模組會從 IISInstall.ps1 指令碼執行 InstallIIS,如 functionScript 中所定義。 ASP.NET 應用程式本身會依 Web Deploy 套件提供,也是從 GitHub 下載,如 WebDeployPackagePath 中所定義:

部署 Bicep 檔案

  1. 將 Bicep 檔案以 main.bicep 儲存至本機電腦。

  2. 使用 Azure CLI 或 Azure PowerShell 部署 Bicep 檔案。

    az group create --name exampleRG --location eastus
    az deployment group create --resource-group exampleRG --template-file main.bicep --parameters vmssName=<vmss-name>
    

    <vmss-name> 取代為虛擬機器擴展集的名稱。 其長度必須為 3-61 個字元,且在 Azure 中全域是唯一的。 系統將會提示您輸入 adminPassword

    注意

    當部署完成時,您應該會看到指出部署成功的訊息。 可能需要 10-15 分鐘才能建立虛擬機器擴展集,並套用延伸模組來設定應用程式。

驗證部署

若要查看作用中的虛擬機器擴展集,請在網頁瀏覽器中存取範例 Web 應用程式。 使用 Azure CLI 或 Azure PowerShell 取得負載平衡器的公用 IP 位址。

az network public-ip show --resource-group exampleRG

http://publicIpAddress/MyApp 的格式,在網頁瀏覽器中輸入負載平衡器的公用 IP 位址。 負載平衡器會將流量散發至您的其中一個 VM 執行個體,如下列範例所示:

Running IIS site

清除資源

不再需要時,請使用 Azure 入口網站、Azure CLI 或 Azure PowerShell 來移除資源群組和其資源。

az group delete --name exampleRG

下一步

在此快速入門中,您已使用 Bicep 檔案建立 Windows 虛擬機器擴展集,並使用 PowerShell DSC 延伸模組在 VM 執行個體上安裝基本 ASP.NET 應用程式。 若要深入了解,請繼續執行有關於如何建立和管理 Azure 虛擬機器擴展集的教學課程。