サブスクリプション間で「イメージ」リソースをコピーする

こんにちは。Azure サポートチームの比留間です。
管理ディスク(Managed Disks) の登場に伴って使用可能になった「イメージ」の機能によって、お客様の任意に VM のカスタムイメージを作成し管理することが比較的容易に行えるようになりました。
(「イメージ」については、こちらをご参照下さい。)

心血注いで作ったイメージを、是非他のサブスクリプションでも使い倒したい! というのは当然あり得るご要望かと思います。しかしながら、申し訳ございません。現時点では「イメージ」を直接他のサブスクリプションに持って行く機能は準備中の段階にあります。
そこで、少しでもご要望に近い操作を行えるような Azure Powershell スクリプトのサンプルをご紹介いたします。

使用に当たりましては、以下の点にご留意ください。

  • 後述します処理の性質上、「イメージ」作成の元ネタとなった 「ディスク」リソースが削除されていない場合にのみ使用が可能です。
  • コピー元、コピー先のサブスクリプションの双方で、「共同管理者」の権限が必要になります。
  • そして例によって 本情報の内容(添付文書、リンク先などを含む)は、更新日時点でのものであり、予告なく変更される場合があります。 また、あくまでもサンプルとしてのご提供となりますことをご了承ください。

処理の内容:
このスクリプトは「イメージ」リソースを直接サブスクリプション間コピーするものではなく、以下の処理の組み合わせによって同等の結果を擬似的に実現するものです。

  • コピー対象となる「イメージ」のメタデータから、元ネタとなったOS ディスクおよび、データディスクのリソースIDを割り出します。
  • 割り出されたリソースIDを元に、ディスクのスナップショットをコピー先のサブスクリプションに作成します。
  • コピーされたスナップショットを元に「イメージ」を作成します。

では、お待ちかね、スクリプトの本体です。

 # パラメーター。お客様の環境に即して設定を変更してください。
$SourceImageName = "イメージの名前"
$SourceResourceGroupName = "コピー元リソースグループ名"
$SourceSubscription = "コピー元サブスクリプションID"
$DestinationSubscription = "コピー先サブスクリプションID"
$DestinationResourceGroupName = "コピー先リソースグループ名"

# コピー元ディスクの ID と スナップショットの初期化
$sourceDataDiskIds = @()
$dataDiskSnapshots = @()

# コピー元サブスクリプションのコンテキストに変更
Select-AzureRmSubscription -SubscriptionId $SourceSubscription

# コピー対象となる「イメージ」リソースの取得
$sourceImage = Get-AzureRmImage -ResourceGroupName $SourceResourceGroupName -ImageName $SourceImageName

# OS ディスクのリソース ID の取得
$sourceOsDiskId = $sourceImage.StorageProfile.OsDisk.ManagedDisk.Id

# データディスクが含まれる場合は、そのリソース ID を取得
foreach($dataDisk in $sourceImage.StorageProfile.DataDisks)
{
    $sourceDataDiskIds += $dataDisk.ManagedDisk.Id
}

# コピー先サブスクリプションのコンテキストに変更
Select-AzureRmSubscription -SubscriptionId $DestinationSubscription

# コピー先サブスクリプションに OS ディスクのスナップショットを作成
$snapshotName = ($sourceOsDiskId -replace ".*/Microsoft.Compute/disks/") + "-Moved-OS"
Write-Output "Snapshotting OS disk in destination subscription: $snapshotName"
$snapshotConfig = New-AzureRmSnapshotConfig -SourceResourceId $sourceOsDiskId -Location $sourceImage.Location -CreateOption Copy
$osDiskSnapshot = New-AzureRmSnapshot -ResourceGroupName $DestinationResourceGroupName -SnapshotName $snapshotName -Snapshot $snapshotConfig

# コピー先サブスクリプションにデータディスクのスナップショットを作成
foreach($managedDiskId in $sourceDataDiskIds)
{
    $snapshotName = ($managedDiskId -replace ".*/Microsoft.Compute/disks/") + "-Moved-Data"
    Write-Output "Snapshotting data disk in destination subscription: $snapshotName"
    $snapshotConfig = New-AzureRmSnapshotConfig -SourceResourceId $managedDiskId -Location $sourceImage.Location -CreateOption Copy
    $dataDiskSnapshots += New-AzureRmSnapshot -ResourceGroupName $DestinationResourceGroupName -SnapshotName $snapshotName -Snapshot $snapshotConfig
}

# 「イメージ」の Config の作成と、OS ディスクのスナップショットの「イメージ」への追加
$newImageConfig = New-AzureRmImageConfig -Location $sourceImage.Location
$newImageConfig = Set-AzureRmImageOsDisk -Image $newImageConfig -OsState Generalized -SnapshotId $osDiskSnapshot.Id

# データディスクには LUN を割り当てる必要があります。LUN 0 から開始。
$lun = 0

# イメージにデータディスクのスナップショットを追加。
foreach ($dataDiskSnapshot in $dataDiskSnapshots)
{
    $newImageConfig = Add-AzureRmImageDataDisk -Image $newImageConfig -SnapshotId $dataDiskSnapshot.Id -Lun $lun
    $lun++
}

# 「イメージ」を作成。
New-AzureRmImage -ImageName ($SourceImageName + "-Moved") -ResourceGroupName $DestinationResourceGroupName -Image $newImageConfig

検証や運用のお役に少しでもお役に立てば幸いです。

嗚呼、また文字ばっかりの投稿になってしまった…