创建 Windows 映像并将其分发到 Azure Compute Gallery

适用于:✔️ Windows VM

在本文中,你将了解如何使用 Azure VM 映像生成器和 Azure PowerShell 在 Azure Compute Gallery(以前称为共享映像库)中创建映像版本,然后全局分发此映像。 也可以使用 Azure CLI 来实现此目的。

为了配置映像,本文使用可在 armTemplateWinSIG.json 中找到的 JSON 模板。 你将下载并编辑模板的本地版本,因此还将使用本地 PowerShell 会话。

此模板使用 sharedImage 作为模板的 distribute 部分的值,以便将映像分发到 Azure Compute Gallery。

VM 映像生成器会自动运行 Sysprep 以通用化映像。 该命令是一个泛型 Sysprep 命令,可根据需要对其进行重写

请注意层自定义的次数。 可以对单个 Windows 映像运行有限次数的 Sysprep 命令。 达到 Sysprep 限制后,必须重新创建 Windows 映像。 有关详细信息,请参阅有关 Sysprep 可运行次数的限制

注册提供程序

若要使用 VM 映像生成器,需要注册提供程序。

  1. 检查提供程序注册情况。 确保都返回“已注册”。

    Get-AzResourceProvider -ProviderNamespace Microsoft.VirtualMachineImages | Format-table -Property ResourceTypes,RegistrationState
    Get-AzResourceProvider -ProviderNamespace Microsoft.Storage | Format-table -Property ResourceTypes,RegistrationState 
    Get-AzResourceProvider -ProviderNamespace Microsoft.Compute | Format-table -Property ResourceTypes,RegistrationState
    Get-AzResourceProvider -ProviderNamespace Microsoft.KeyVault | Format-table -Property ResourceTypes,RegistrationState
    Get-AzResourceProvider -ProviderNamespace Microsoft.Network | Format-table -Property ResourceTypes,RegistrationState
    Get-AzResourceProvider -ProviderNamespace Microsoft.ContainerInstance | Format-table -Property ResourceTypes,RegistrationState
    
  2. 如果未返回“已注册”,请运行以下命令注册提供程序:

    Register-AzResourceProvider -ProviderNamespace Microsoft.VirtualMachineImages
    Register-AzResourceProvider -ProviderNamespace Microsoft.Storage
    Register-AzResourceProvider -ProviderNamespace Microsoft.Compute
    Register-AzResourceProvider -ProviderNamespace Microsoft.KeyVault
    Register-AzResourceProvider -ProviderNamespace Microsoft.ContainerInstance
    
  3. 安装 PowerShell 模块:

    'Az.ImageBuilder', 'Az.ManagedServiceIdentity' | ForEach-Object {Install-Module -Name $_ -AllowPrerelease}
    

创建变量

因为你将重复使用某些信息,所以要创建一些变量来存储这些信息。

将变量(如 usernamevmpassword)的值替换为自己的信息。

# Get existing context
$currentAzContext = Get-AzContext

# Get your current subscription ID. 
$subscriptionID=$currentAzContext.Subscription.Id

# Destination image resource group
$imageResourceGroup="aibwinsig"

# Location
$location="chinanorth3"

# Image distribution metadata reference name
$runOutputName="aibCustWinManImg02ro"

# Image template name
$imageTemplateName="helloImageTemplateWin02ps"

# Distribution properties object name (runOutput).
# This gives you the properties of the managed image on completion.
$runOutputName="winclientR01"

# Create a resource group for the VM Image Builder template and Azure Compute Gallery
New-AzResourceGroup `
   -Name $imageResourceGroup `
   -Location $location

创建用户分配的标识,并在资源组上设置权限

VM 映像生成器使用提供的用户标识将映像注入到 Azure Compute Gallery 中。 在此示例中将创建一个 Azure 角色定义,该定义具有分发映像的特定操作。 然后将角色定义分配给用户标识。

# setup role def names, these need to be unique
$timeInt=$(get-date -UFormat "%s")
$imageRoleDefName="Azure Image Builder Image Def"+$timeInt
$identityName="aibIdentity"+$timeInt

## Add an Azure PowerShell module to support AzUserAssignedIdentity
Install-Module -Name Az.ManagedServiceIdentity

# Create an identity
New-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName

$identityNameResourceId=$(Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName).Id
$identityNamePrincipalId=$(Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName).PrincipalId

为标识分配权限以分发映像

使用此命令下载 Azure 角色定义模板,然后使用之前指定的参数对其进行更新。

$aibRoleImageCreationUrl="https://raw.githubusercontent.com/azure/azvmimagebuilder/master/solutions/12_Creating_AIB_Security_Roles/aibRoleImageCreation.json"
$aibRoleImageCreationPath = "aibRoleImageCreation.json"

# Download the configuration
Invoke-WebRequest -Uri $aibRoleImageCreationUrl -OutFile $aibRoleImageCreationPath -UseBasicParsing

((Get-Content -path $aibRoleImageCreationPath -Raw) -replace '<subscriptionID>',$subscriptionID) | Set-Content -Path $aibRoleImageCreationPath
((Get-Content -path $aibRoleImageCreationPath -Raw) -replace '<rgName>', $imageResourceGroup) | Set-Content -Path $aibRoleImageCreationPath
((Get-Content -path $aibRoleImageCreationPath -Raw) -replace 'Azure Image Builder Service Image Creation Role', $imageRoleDefName) | Set-Content -Path $aibRoleImageCreationPath

# Create a role definition
New-AzRoleDefinition -InputFile  ./aibRoleImageCreation.json

# Grant the role definition to the VM Image Builder service principal
New-AzRoleAssignment -ObjectId $identityNamePrincipalId -RoleDefinitionName $imageRoleDefName -Scope "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup"

注意

如果收到此错误:“New-AzRoleDefinition: 已超出角色定义限制。 无法创建更多的角色定义”。请参阅排查 Azure 基于角色的访问控制 (RBAC) 问题

若要将 VM 映像生成器与 Azure Compute Gallery 配合使用,需要现有的库和映像定义。 VM 映像生成器不会创建库和映像定义。

如果还没有可使用的库和映像定义,请先创建它们。

# Gallery name
$sigGalleryName= "myIBSIG"

# Image definition name
$imageDefName ="winSvrimage"

# Additional replication region
$replRegion2="chinanorth"

# Create the gallery
New-AzGallery `
   -GalleryName $sigGalleryName `
   -ResourceGroupName $imageResourceGroup  `
   -Location $location

# Create the image definition
New-AzGalleryImageDefinition `
   -GalleryName $sigGalleryName `
   -ResourceGroupName $imageResourceGroup `
   -Location $location `
   -Name $imageDefName `
   -OsState generalized `
   -OsType Windows `
   -Publisher 'myCompany' `
   -Offer 'WindowsServer' `
   -Sku 'WinSrv2019'

下载并配置模板

下载 JSON 模板,并使用自己的变量对它进行配置。


$templateFilePath = "armTemplateWinSIG.json"

Invoke-WebRequest `
   -Uri "https://raw.githubusercontent.com/azure/azvmimagebuilder/master/quickquickstarts/1_Creating_a_Custom_Win_Shared_Image_Gallery_Image/armTemplateWinSIG.json" `
   -OutFile $templateFilePath `
   -UseBasicParsing

(Get-Content -path $templateFilePath -Raw ) `
   -replace '<subscriptionID>',$subscriptionID | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<rgName>',$imageResourceGroup | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<runOutputName>',$runOutputName | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<imageDefName>',$imageDefName | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<sharedImageGalName>',$sigGalleryName | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<region1>',$location | Set-Content -Path $templateFilePath
(Get-Content -path $templateFilePath -Raw ) `
   -replace '<region2>',$replRegion2 | Set-Content -Path $templateFilePath
((Get-Content -path $templateFilePath -Raw) -replace '<imgBuilderId>',$identityNameResourceId) | Set-Content -Path $templateFilePath

创建映像版本

你的模板必须提交到服务。 以下命令将下载任何依赖项目(例如脚本),并将其存储在前缀为“IT_”的暂存资源组中。

New-AzResourceGroupDeployment `
   -ResourceGroupName $imageResourceGroup `
   -TemplateFile $templateFilePath `
   -ApiVersion "2022-02-14" `
   -imageTemplateName $imageTemplateName `
   -svclocation $location

对模板调用“运行”以生成映像。

Invoke-AzResourceAction `
   -ResourceName $imageTemplateName `
   -ResourceGroupName $imageResourceGroup `
   -ResourceType Microsoft.VirtualMachineImages/imageTemplates `
   -ApiVersion "2022-02-14" `
   -Action Run

创建映像并将其复制到这两个区域,这可能需要一段时间。 等待此部分完成,然后开始创建 VM。

Get-AzImageBuilderTemplate -ImageTemplateName $imageTemplateName -ResourceGroupName $imageResourceGroup |
  Select-Object -Property Name, LastRunStatusRunState, LastRunStatusMessage, ProvisioningState

创建 VM

根据使用 VM 映像生成器创建的映像版本创建 VM。

  1. 获取所创建的映像版本:

    $imageVersion = Get-AzGalleryImageVersion `
    -ResourceGroupName $imageResourceGroup `
    -GalleryName $sigGalleryName `
    -GalleryImageDefinitionName $imageDefName
    $imageVersionId = $imageVersion.Id
    
  2. 在此映像复制到的第二个区域中创建 VM:

    $vmResourceGroup = "myResourceGroup"
    $vmName = "myVMfromImage"
    
    # Create user object
    $cred = Get-Credential -Message "Enter a username and password for the virtual machine."
    
    # Create a resource group
    New-AzResourceGroup -Name $vmResourceGroup -Location $replRegion2
    
    # Network pieces
    $subnetConfig = New-AzVirtualNetworkSubnetConfig -Name mySubnet -AddressPrefix 192.168.1.0/24
    $vnet = New-AzVirtualNetwork -ResourceGroupName $vmResourceGroup -Location $replRegion2 `
    -Name MYvNET -AddressPrefix 192.168.0.0/16 -Subnet $subnetConfig
    $pip = New-AzPublicIpAddress -ResourceGroupName $vmResourceGroup -Location $replRegion2 `
    -Name "mypublicdns$(Get-Random)" -AllocationMethod Static -IdleTimeoutInMinutes 4
    $nsgRuleRDP = New-AzNetworkSecurityRuleConfig -Name myNetworkSecurityGroupRuleRDP  -Protocol Tcp `
    -Direction Inbound -Priority 1000 -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * `
    -DestinationPortRange 3389 -Access Deny
    $nsg = New-AzNetworkSecurityGroup -ResourceGroupName $vmResourceGroup -Location $replRegion2 `
    -Name myNetworkSecurityGroup -SecurityRules $nsgRuleRDP
    $nic = New-AzNetworkInterface -Name myNic -ResourceGroupName $vmResourceGroup -Location $replRegion2 `
    -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $nsg.Id
    
    # Create a virtual machine configuration using $imageVersion.Id to specify the image
    $vmConfig = New-AzVMConfig -VMName $vmName -VMSize Standard_D1_v2 | `
    Set-AzVMOperatingSystem -Windows -ComputerName $vmName -Credential $cred | `
    Set-AzVMSourceImage -Id $imageVersion.Id | `
    Add-AzVMNetworkInterface -Id $nic.Id
    
    # Create a virtual machine
    New-AzVM -ResourceGroupName $vmResourceGroup -Location $replRegion2 -VM $vmConfig
    

验证自定义

使用创建 VM 时设置的用户名和密码创建与 VM 的远程桌面连接。 在 VM 中打开“命令提示符”窗口并运行以下命令:

dir c:\

应该会看到一个名为 buildActions 的目录,该目录是在映像自定义期间创建的。

清理资源

注意

如果你现在就想要尝试重新自定义映像版本以创建同一映像的新版本,请跳过此处概述的步骤并转到使用 VM 映像生成器创建另一个映像版本

如果不再需要按照本文中的过程创建的资源,则可以删除这些资源。

以下过程会删除你已创建的映像以及所有其他资源文件。 在删除资源之前,请确保已完成此部署。

首先删除资源组模板。 如果不这样操作,则不会清理 VM 映像生成器使用的暂存资源组 (IT_)。

  1. 获取映像模板的 ResourceID。

    $resTemplateId = Get-AzResource -ResourceName $imageTemplateName -ResourceGroupName $imageResourceGroup -ResourceType Microsoft.VirtualMachineImages/imageTemplates -ApiVersion "2022-02-14"
    
  2. 删除映像模板。

    Remove-AzResource -ResourceId $resTemplateId.ResourceId -Force
    
  3. 删除角色分配。

    Remove-AzRoleAssignment -ObjectId $identityNamePrincipalId -RoleDefinitionName $imageRoleDefName -Scope "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup"
    
  4. 删除定义。

    Remove-AzRoleDefinition -Name "$identityNamePrincipalId" -Force -Scope "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup"
    
  5. 删除标识。

    Remove-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName -Force
    
  6. 删除该资源组。

    Remove-AzResourceGroup $imageResourceGroup -Force
    

后续步骤

若要更新依照本文创建的映像版本,请参阅使用 VM 映像生成器创建其他映像版本