Azure Windows VM のイメージを取得しAzure Compute Gallery に格納する
Azure Windows VM のイメージを他のVM でも流用したいときがあります。今回はAzure Windows VM のイメージを取得し、Azure Compute Gallery に格納後、イメージからAzure VM を作成するまでを説明します。
実施環境
Azure VM OS | Windows Server 2025 Datacenter Azure Edition |
---|---|
Azure CLI | 2.67.0 |
Bicep CLI | 0.32.4 |
前提条件
- Azure リソース作成用のサブスクリプションがあること
- Azure CLI の実行環境があること
Azure Compute Gallery とは
Azure Compute Gallery はAzure VM のイメージやアプリケーションを管理するサービスです。Compute Gallery を利用することで、サブスクリプションやテナント、パブリックへのAzure VM イメージ、アプリケーションの共有、管理が容易となります。
Azure Compute Gallery でVM イメージを管理するには、VM のイメージ定義の作成が必要です。VM 定義内でイメージのソース、OS 種別、リリースノート、最小、最大メモリを定義しバージョン管理します。バージョンごとのイメージ管理を行えるため、イメージからVM を作成する場合は特定のバージョンのVM を作成できます。VM イメージの管理ではレプリカで利用可能なVM 数を指定することで、スケーリング時のオーバーロードの削減もできます。アプリケーションを管理する場合、VM とアプリケーションを分離して管理できるため、アプリケーション更新時のVM イメージ更新の工数を削減できます。
Azure Compute Gallery はRBAC 共有、RBAC + 直接共有ギャラリー (プレビュー)、RBAC + コミュニティギャラリーの公開範囲があります。各公開範囲の違いは以下のとおりとなります。
ユーザー | グループ | サービスプリンシパル | 特定のサブスクリプション (または) テナント内のすべてのユーザー | Azure のすべてのユーザーと公に | |
---|---|---|---|---|---|
RBAC | 〇 | 〇 | 〇 | × | × |
RBAC + 直接共有ギャラリー | 〇 | 〇 | × | 〇 | × |
RBAC + コミュニティギャラリー | 〇 | 〇 | 〇 | × | 〇 |
Azure Compute Gallery はグローバルにレプリケーションを行い、可用性ゾーンもサポートしています。これらの機能を利用することで、VM イメージ展開の可用性を向上できます。
Azure Compute Gallery 自体の料金は無料ですが、イメージのレプリカを格納するストレージコストと他リージョンへの初回レプリケートに課金が発生します。詳細な料金は以下URL を参照してください。
Azure VM のイメージについて
Azure VM のOS イメージには一般化されたイメージと特殊化されたイメージの2種類があります。一般化されたイメージはOS からユーザー・シンの固有情報を削除し、複数のサーバー (VM) で利用できるイメージです。特殊化されたイメージはユーザー・マシンの固有情報を残し、特定のサーバー(VM) でのみ利用できるイメージです。
Azure VM で一般化されたイメージを準備する場合、Windows OS ではSysprep ツール、Linux OS ではMicrosoft Azure Linux Agent を利用します。これらの作業はVM イメージのキャプチャ時に実施されないため、ユーザー側での手動対応が必要です。また、一部のサードパーティー製ソフトウェアではSysprep などで固有情報を削除しないものもあるため、これらのソフトウェアを利用する場合、VM 作成後にソフトウェアを導入するなどの工夫する必要があります (ウィルス対策ソフトや資産管理系のソフト、エージェントの類、など)。
Azure VM のイメージキャプチャはAzure Portal、Azure CLI、Azure PowerShell、各種IaC ツールで実施できます。Azure VM からイメージキャプチャ後、Azure VM のStatus がgeneralized となりVM の再起動ができなくなります。そのため、想定外の事象に対応する場合は事前にスナップショットの取得やバックアップの作成を行うようにしてください。
今回の構成
今回はIIS を導入したAzure Windows VM を一般化し、Azure Compute Gallery へ格納します。VM イメージの格納後、Compute Gallery のVM イメージを利用しVM を作成します。Azure リソースの作成はBicep (Azure Verified Modules) で行い、VM イメージの一般化、VM イメージ格納を手動で実施します。
リソースプロバイダーの登録
今回はAzure Verified Modules でAzure Windows VM を作成するため、EncryptionAtHost 機能を有効化します。既に有効化している場合はこの手順をスキップしてください。
# Microsoft.Compute/EncryptionAtHostを登録する
az feature register --namespace Microsoft.Compute --name EncryptionAtHost
# EncryptionAtHostの状態を確認する
# StateがRegisteredであること
az feature list -o table --query "[?contains(name, 'Microsoft.Compute/EncryptionAtHost')].{Name:name,State:properties.state}"
# リソースプロバイダーを登録する
az provider register --namespace Microsoft.Compute
もしリソースプロバイダーを利用したくない場合はBicep テンプレートファイル作成時に「securityType: ''」と「encryptionAtHost: false」を指定し、ホスト暗号化を無効化してください。
Azure Windows VM、Azure Comute Gallery の作成
初めにリソースグループを作成し、VM イメージ作成用のAzure VM とAzure Compute Gallery を作成します。Bicep テンプレートファイルとパラメーターファイルのフォルダ構成は以下のとおりです。
.
├── main.bicep
└── parameters
└── main.bicepparam
Bicep パラメーターファイルは以下のとおりです。今回は検証のためAzure VM のパスワードをハードコードしていますが、実務などで利用する場合はSSH キーやEntra ID 認証を利用するようにしてください。
using '../main.bicep'
// リソースグループのパラメーター
param resourceGroupParam = {
name: 'rg-vmimage'
}
// コンピューティングギャラリー、イメージ定義のパラメーター
param computeGalleryParam = {
name: 'galvmimage'
identifier: {
offer: 'WindowsServer'
publisher: 'MicrosoftWindowsServer'
sku: '2025-datacenter-g2'
}
isAcceleratedNetworkSupported: true
isHibernateSupported: true
memory: {
max: 16
min: 4
}
imagename: 'az-winsrv-iis'
osState: 'Generalized'
osType: 'Windows'
vCPUs: {
max: 8
min: 2
}
}
// ネットワークセキュリティグループのパラメーター
param networkSecurityGroupParam = {
name: 'nsg-vmimage'
securityRules: [
{
name: 'AllowHTTPAccess'
properties: {
access: 'Allow'
description: 'Test HTTP Access'
destinationAddressPrefix: '*'
destinationPortRange: '80'
direction: 'Inbound'
priority: 100
protocol: '*'
sourceAddressPrefix: '*'
sourcePortRange: '*'
}
}
{
name: 'AllowRDPAccess'
properties: {
access: 'Allow'
description: 'Test RDP Access'
destinationAddressPrefix: '*'
destinationPortRange: '3389'
direction: 'Inbound'
priority: 200
protocol: '*'
sourceAddressPrefix: '*'
sourcePortRange: '*'
}
}
]
}
// 仮想ネットワークのパラメーター
param virtualNetworkParam = {
name: 'vnet-vmimage'
addressPrefixes: [
'10.0.0.0/16'
]
subnets: [
{
name: 'sub-vm'
addressPrefix: '10.0.0.0/24'
}
]
}
// 仮想マシンのパラメーター
param virtualMachineParam = {
vmname: 'vm-vmimage'
adminUser: 'azureuser'
imageReference: {
publisher: 'MicrosoftWindowsServer'
offer: 'WindowsServer'
sku: '2025-datacenter-azure-edition'
version: 'latest'
}
nicConfigurations: [
{
nicname: 'nic-vmimage'
ipConfigurations: [
{
name: 'ipconfig01'
pipConfiguration: {
pipname: 'pip-vmimage'
skuName: 'Standard'
publicIpNameSuffix: ''
zones: []
}
}
]
nicSuffix: ''
}
]
osDisk: {
name: 'osdisk-vmimage'
caching: 'ReadWrite'
diskSizeGB: 128
managedDisk: {
storageAccountType: 'Standard_LRS'
}
}
osType: 'Windows'
vmSize: 'Standard_D2s_v3'
zone: 0
}
param adminPassword = 'rQAZxs4w@Age'
Bicep テンプレートファイルは以下のとおりです。
targetScope = 'subscription'
@description('リソースグループのパラメーター')
param resourceGroupParam object
@description('コンピューティングギャラリー、イメージ定義のパラメーター')
param computeGalleryParam object
@description('ネットワークセキュリティグループのパラメーター')
param networkSecurityGroupParam object
@description('仮想ネットワークのパラメーター')
param virtualNetworkParam object
@description('仮想マシンのパラメーター')
param virtualMachineParam object
@secure()
@description('仮想マシンの管理者ユーザーパスワード')
param adminPassword string
// リソースグループの作成
module rg 'br/public:avm/res/resources/resource-group:0.4.0' = {
scope: subscription()
name: resourceGroupParam.name
params: {
name: resourceGroupParam.name
}
}
// Azure コンピューティングギャラリー、イメージ定義の作成
module gallery 'br/public:avm/res/compute/gallery:0.8.1' = {
scope: resourceGroup(resourceGroupParam.name)
name: computeGalleryParam.name
dependsOn: [
rg
]
params: {
name: computeGalleryParam.name
images: [
{
hyperVGeneration: 'V2'
identifier: computeGalleryParam.identifier
isAcceleratedNetworkSupported: computeGalleryParam.isAcceleratedNetworkSupported
isHibernateSupported: computeGalleryParam.isHibernateSupported
memory: computeGalleryParam.memory
name: computeGalleryParam.imagename
osState: computeGalleryParam.osState
osType: computeGalleryParam.osType
vCPUs: computeGalleryParam.vCPUs
}
]
}
}
// ネットワークセキュリティグループ(NSG)の作成
// IIS用のHTTPとSysprep用のRDPを開放する
module nsg 'br/public:avm/res/network/network-security-group:0.5.0' = {
scope: resourceGroup(resourceGroupParam.name)
name: networkSecurityGroupParam.name
dependsOn: [
rg
]
params: {
name: networkSecurityGroupParam.name
securityRules: networkSecurityGroupParam.securityRules
}
}
// 仮想ネットワーク、サブネットの作成
module vnet 'br/public:avm/res/network/virtual-network:0.5.2' = {
scope: resourceGroup(resourceGroupParam.name)
name: virtualNetworkParam.name
dependsOn: [
rg
]
params: {
name: virtualNetworkParam.name
addressPrefixes: virtualNetworkParam.addressPrefixes
subnets: [
{
name: virtualNetworkParam.subnets[0].name
addressPrefix: virtualNetworkParam.subnets[0].addressPrefix
networkSecurityGroupResourceId: nsg.outputs.resourceId
}
]
}
}
// イメージ作成用VMの作成
// VM作成時にNICも作成する
module vm 'br/public:avm/res/compute/virtual-machine:0.11.0' = {
scope: resourceGroup(resourceGroupParam.name)
name: virtualMachineParam.vmname
dependsOn: [
rg
]
params: {
name: virtualMachineParam.vmname
adminUsername: virtualMachineParam.adminUser
adminPassword: adminPassword
extensionAadJoinConfig: {
enabled: false
}
imageReference: virtualMachineParam.imageReference
nicConfigurations: [
{
name: virtualMachineParam.nicConfigurations[0].nicname
ipConfigurations: [
{
name: virtualMachineParam.nicConfigurations[0].ipConfigurations[0].name
pipConfiguration: {
name: virtualMachineParam.nicConfigurations[0].ipConfigurations[0].pipConfiguration.pipname
publicIpNameSuffix: virtualMachineParam.nicConfigurations[0].ipConfigurations[0].pipConfiguration.publicIpNameSuffix
zones: virtualMachineParam.nicConfigurations[0].ipConfigurations[0].pipConfiguration.zones
}
subnetResourceId: vnet.outputs.subnetResourceIds[0]
}
]
nicSuffix: ''
}
]
osDisk: virtualMachineParam.osDisk
osType: virtualMachineParam.osType
vmSize: virtualMachineParam.vmSize
zone: virtualMachineParam.zone
}
}
Bicep テンプレートファイル、パラメーターファイルの準備後、Azure リソースを作成します。
# BicepテンプレートファイルでデプロイするAzureリソースを確認する
az deployment sub what-if -l japaneast -f main.bicep -p parameters/main.bicepparam
# Azureリソースをデプロイする
az deployment sub create -l japaneast -f main.bicep -p parameters/main.bicepparam
Azure VM にIIS をインストール
Azure リソース作成後、VM にIIS をインストールします。Azure CLI からVM コマンドを実行しインストールします。
# IISをインストールする
az vm run-command invoke --command-id RunPowerShellScript --name vm-vmimage --resource-group rg-vmimage --scripts "Install-WindowsFeature -Name Web-Server"
Azure Windows VM の一般化、VM イメージの取得
IIS のインストール後、Azure Windows VM にRDP 接続し、Sysprep を使いVM を一般化します。Sysprep 後に一度でもVM を起動してしまうと初期設定画面が始まるため、Sysprep 後にAzure VM を起動しないよう注意してください。
REM Windows Serverを一般化する
cd C:\Windows\System32\Sysprep
sysprep /oobe /generalize /shutdown
OS イメージの一般化後、Azure VM のステータスをGeneralized に変更します。
# Azure VMの割り当てを解除する
az vm deallocate --resource-group rg-vmimage --name vm-vmimage
# Azure VMのステータスを確認する
# VM deallocated と表示されること
az vm get-instance-view --resource-group rg-vmimage --name vm-vmimage --query "instanceView.statuses[?starts_with(code, 'PowerState/')].displayStatus" --output tsv
# Azure VMのステータスを一般化する
az vm generalize --resource-group rg-vmimage --name vm-vmimage
Azure VM の一般化後、仮想マシンのイメージからCompute Gallery の新しいイメージバージョンを作成します。
# Azure VMから新しいイメージバージョンを作成する
az sig image-version create \
--resource-group rg-vmimage \
--gallery-name galvmimage \
--gallery-image-definition az-winsrv-iis \
--gallery-image-version 1.0.1 \
--virtual-machine $(az vm show --resource-group rg-vmimage --name vm-vmimage --query "id" --output tsv)
Compute Gallery のイメージからAzure VM を作成する
Compute Gallery へVM イメージ格納後、格納したイメージを使いAzure VM を作成します。今回はAzure CLI を利用しAzure VM を作成します。Compute Gallery のイメージを利用する場合、Azure CLI の --image オプションで指定したバージョンのリソースID を指定します (動作確認用のためパスワードはそのままにしています)。
Compute Gallery のイメージ定義を利用するにはCompute Gallery のイメージ定義に対し読み取り権限が必要となりますため、事前に付与しておいてください。
# Compute GalleryのVMイメージからAzure VMを作成する
az vm create \
--resource-group rg-vmimage \
--name vm-fromgal \
--image $(az sig image-version show --resource-group rg-vmimage --gallery-image-definition az-winsrv-iis --gallery-image-version 1.0.1 --gallery-name galvmimage --query "id" --output tsv) \
--vnet-name vnet-vmimage \
--subnet sub-vm \
--admin-username azureuser \
--admin-password rQAZxs4w@Age
VM 作成後、RDP でVM にログインしサーバーマネージャーにIIS があることを確認します。
リソースのクリーンアップ
動作確認後、各種リソースをクリーンアップします。
# リソースをクリーンアップする
az group delete --resource-group rg-vmimage
まとめ
- Azure Compute Gallery はAzure VM のイメージ、アプリケーションの管理を行うサービス
- Azure VM のVM イメージには一般化されたイメージと特殊化されたイメージがある
- Azure VM から一般化されたVM イメージを作成する場合、Sysprep 後にAzure VM のステータスをGeneralized に変更する
- Compute Gallery のイメージを利用するには、VM イメージ定義のID を指定して作成する