Copiar máquinas virtuales Azure entre suscripciones

Por Ignacio Escudero
Support Manager en OpenSistemas

Es muy normal y útil tener alguna cuenta demo de Microsoft Azure con la que poder usar tu suscripción durante unos meses y tomar contacto con su plataforma. Empiezas a seguir tutoriales, crear servicios, máquinas pero, en algún momento, posiblemente quieras migrar o copiar las máquinas a otro entorno, por ejemplo, para poner en producción.

Empiezan los problemas, ¿cómo migro todo a otra cuenta? Si lo que quieres es ceder tu cuenta a otra persona o entidad no hay ningún problema, ya que puedes ponerte en contacto con Microsoft y ellos la “fusionan”. Pero y si solo quiero copiar “alguna de mis máquinas virtuales”, no te preocupes, es una tarea un poco más engorrosa, pero se puede realizar.

El primer obstáculo es tener PowerShell para Azure. Si usas Linux tienes que buscar un SO de Microsoft que soporte PowerShell. No vale el Windows 98 que tenías cuando eras adolescente… Gasta algo de dinero, compra una licencia y ponte una máquina virtual sobre tu Linux, por ejemplo.

Hay varios tutoriales paso a paso con los comandos que debes usar, como este, pero hay varias cosas que no funcionan correctamente… Pasemos a explicarlas.

Lo primero, acceso a tu cuenta de origen y de destino:

Add-AzureAccount

Y selección de la cuenta que ahora vamos a usar, primero la de origen, para eso:
Get-AzureSubscription

Aquí toma nota del
SubscriptionName

que tienen las cuentas que vas a usar, pues tienes que “activarla” para ejecutar los comandos. Se activa con:

Select-AzureSubscription -Current -SubscriptionName elnombredetusubscripcion
Get-AzureVM

Si todo ha ido bien, ya has podido listar todas tus VM y localizar la que te interesa, ahora empieza lo bueno.

Siguiendo el tutorial que enlazamos más arriba tendrías que crear las siguientes variables:

$vmName = "EL_NOMBRE_DE_TU_VM"
$serviceName = "EL_NOMBRE_DE_TU_CLOUD_SERVICE"
$destServiceName = "EL_NOMBRE_DEL_NUEVO_CLOUD_SERVICE"
$workingDir = (Get-Location).Path

Con la última:
$workingDir = (Get-Location).Path

puedes tener problemas, ya que la localización que te crea puede que no permita escribir y luego no vas a poder exportar correctamente la VM. Te recomiendo algo como:
$workingDir= "C:\ExportVMs"
if (!(Test-Path -Path $workingDir)) {

New-Item -Path $workingDir -ItemType Directory
}

Continuamos con:

$sourceVm = Get-AzureVM –ServiceName $serviceName –Name $vmName
$vmConfigurationPath = $workingDir + "\" + $vm.Name + ".xml"
$sourceVm | Export-AzureVM -Path $vmConfigurationPath
$sourceOSDisk = $sourceVm.VM.OSVirtualHardDisk
$sourceDataDisks = $sourceVm.VM. DataVirtualHardDisks

Para obtener la cuenta de almacenamiento de tu VM:

$sourceStorageName = $sourceOSDisk.MediaLink.Host -split "\." | select -First 1
$sourceStorageAccount = Get-AzureStorageAccount –StorageAccountName $sourceStorageName
$sourceStorageKey = (Get-AzureStorageKey -StorageAccountName $sourceStorageName).Primary

Asegúrate de apagar la máquina virtual:

Stop-AzureVM –ServiceName $serviceName –Name $vmName -Force

Ya vamos a proceder a copia la VM y necesitamos cambiar de suscripción de Azure:

Select-AzureSubscription -SubscriptionName elnombredetusubscripcionnueva

Ubicación de la cuenta de almacenamiento. Suponemos que la copiamos a la misma región pero en diferente suscripción:

$location = $sourceStorageAccount.Location

Creamos una nueva cuenta de almacenamiento en la nueva suscripción:

$destStorageAccount = Get-AzureStorageAccount | ? {$_.Location -eq $location} | select -first 1
if ($destStorageAccount -eq $null)
{
$destStorageName = nuevacuentadealmacenamiento
New-AzureStorageAccount -StorageAccountName $destStorageName -Location $location
$destStorageAccount = Get-AzureStorageAccount -StorageAccountName $destStorageName
}

$destStorageName = $destStorageAccount.StorageAccountName
$destStorageKey = (Get-AzureStorageKey -StorageAccountName $destStorageName).Primary

Y todas las nuevas variables necesarias para los siguientes pasos:

$sourceContext = New-AzureStorageContext –StorageAccountName $sourceStorageName -StorageAccountKey $sourceStorageKey
$destContext = New-AzureStorageContext –StorageAccountName $destStorageName -StorageAccountKey $destStorageKey

Verificaciones:

if ((Get-AzureStorageContainer -Context $destContext -Name vhds -ErrorAction SilentlyContinue) -eq $null)
{
New-AzureStorageContainer -Context $destContext -Name vhds
}

Ya va quedando menos, nos disponemos a copiar:

$allDisks = @($sourceOSDisk) + $sourceDataDisks
$destDataDisks = @()
foreach($disk in $allDisks)
{
$blobName = $disk.MediaLink.Segments[2]
$targetBlob = Start-CopyAzureStorageBlob -SrcContainer vhds -SrcBlob $blobName -DestContainer vhds -DestBlob $blobName -Context $sourceContext -DestContext $destContext -Force
Write-Host "Copying blob $blobName"
$copyState = $targetBlob | Get-AzureStorageBlobCopyState
while ($copyState.Status -ne "Success")
{
$percent = ($copyState.BytesCopied / $copyState.TotalBytes) * 100
Write-Host "Completed $('{0:N2}' -f $percent)%"
sleep -Seconds 5
$copyState = $targetBlob | Get-AzureStorageBlobCopyState
}
If ($disk -eq $sourceOSDisk)
{
$destOSDisk = $targetBlob
}
Else
{
$destDataDisks += $targetBlob
}
}

Registramos los nuevos discos duros para que sean correctamente reconocidos en la nueva suscripción:

Add-AzureDisk -OS $sourceOSDisk.OS -DiskName $sourceOSDisk.DiskName -MediaLocation $destOSDisk.ICloudBlob.Uri
foreach($currenDataDisk in $destDataDisks)
{
$diskName = ($sourceDataDisks | ? {$_.MediaLink.Segments[2] -eq $currenDataDisk.Name}).DiskName
Add-AzureDisk -DiskName $diskName -MediaLocation $currenDataDisk.ICloudBlob.Uri
}

Y finalmente creamos la nueva VM. Mucho cuidado porque puede dar problemas:

Get-AzureSubscription -Current | Set-AzureSubscription -CurrentStorageAccountName $destStorageName
$vmConfig = Import-AzureVM -Path $vmConfigurationPath

Tal vez tengas que haber creado una red antes, si la VM la tenía, retocar el fichero XML para que no use IPs fijas, etc. Todo depende de lo sencilla o compleja que era tu VM de origen.

¡¡¡¡Suerte con las migraciones!!!!