diff --git a/ci/vale/dictionary.txt b/ci/vale/dictionary.txt index 3c95e8aa179..6d65ba5589a 100644 --- a/ci/vale/dictionary.txt +++ b/ci/vale/dictionary.txt @@ -53,6 +53,7 @@ alphanumerics amavis amavisd amd64 +AMIs ananke aniszczyk anonymization @@ -520,6 +521,7 @@ dcid dcs deadman deallocated +deallocating deallocation deathmatch debconf @@ -905,6 +907,7 @@ gopwt goroutine goroutines goto +gparted gpasswd gpc gpg diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-create-snapshot.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-create-snapshot.png new file mode 100644 index 00000000000..8c39dc52013 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-create-snapshot.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-export-button.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-export-button.png new file mode 100644 index 00000000000..b633f04d8cd Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-export-button.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-properties.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-properties.png new file mode 100644 index 00000000000..6628df81989 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-disk-properties.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-generate-url.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-generate-url.png new file mode 100644 index 00000000000..aa2d31e8cba Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-generate-url.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-resource-selected.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-resource-selected.png new file mode 100644 index 00000000000..158e8be1c3b Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-resource-selected.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-rules-list.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-rules-list.png new file mode 100644 index 00000000000..2e82cade3ad Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-nsg-rules-list.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-group-vm-list.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-group-vm-list.png new file mode 100644 index 00000000000..3dc56fd8a9a Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-group-vm-list.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-groups-list.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-groups-list.png new file mode 100644 index 00000000000..a26643b7173 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-resource-groups-list.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-snapshots-page.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-snapshots-page.png new file mode 100644 index 00000000000..b98b6e01fe7 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-snapshots-page.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-disk-selected.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-disk-selected.png new file mode 100644 index 00000000000..1452c4c7e1a Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-disk-selected.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-essentials-size-specs.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-essentials-size-specs.png new file mode 100644 index 00000000000..78aaac3de78 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-essentials-size-specs.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-stop-button.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-stop-button.png new file mode 100644 index 00000000000..f403827caf2 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/azure-vm-stop-button.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/index.md b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/index.md new file mode 100644 index 00000000000..910c843dd3c --- /dev/null +++ b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/index.md @@ -0,0 +1,703 @@ +--- +slug: transfer-azure-virtual-machine-to-akamai-using-disk-images +title: "Transfer Azure Virtual Machine to Akamai Using Disk Images" +description: "Two to three sentences describing your guide." +authors: ["Linode"] +contributors: ["Linode"] +published: 2025-05-28 +keywords: ['list','of','keywords','and key phrases'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +external_resources: +- '[Link Title 1](http://www.example.com)' +- '[Link Title 2](http://www.example.net)' +--- + +In modern cloud computing, virtual machine (VM) migration is a process that enables organizations to transition workloads between cloud platforms to optimize costs, improve performance, or enhance flexibility. By migrating VMs, organizations can select the capabilities of various cloud providers that best satisfy their business needs. + +This guide focuses on migrating a VM from Azure Virtual Machine to Akamai Cloud using disk images and suggests how to plan, execute, and validate the migration. + +## Before You Begin + +1. Log in to your [Akamai Cloud](https://www.linode.com/cfe) account to prepare the destination environment. + +1. Create a [Linode API token (personal access token)](/docs/products/platform/accounts/guides/manage-api-tokens/) so you can authenticate with the Linode CLI. + +1. Install and configure the [Linode CLI](/docs/products/tools/cli/guides/install/) on your local system. + +1. You must have access to an Azure account with sufficient permissions to work with Managed Disks and Storage Accounts. + +1. Install and configure the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) (`az`) to interact with your Azure Virtual Machine instances. + +1. Install [QEMU](https://www.qemu.org/) to convert the exported disk image into a format compatible with Akamai Cloud. + +{{< note >}} +This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you’re not familiar with the `sudo` command, see the [Users and Groups](/docs/guides/linux-users-and-groups/) guide. +{{< /note >}} + +## Preparing Your Azure VM for Migration + +Before migrating, review your Azure environment to ensure compatibility with Akamai Cloud. Note any instance-specific dependencies, such as storage size, image type, or hardware requirements, that may impact the transition. + +Record the configuration details of your Azure VM to help choose an [Akamai Cloud plan](https://www.linode.com/pricing/#compute-shared) that matches your resource needs after migration. + +{{< note >}} +[Images imported into Akamai Cloud](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) must be smaller than 6 GB unzipped or 5 GB zipped. Images exceeding the size limit are rejected during upload and not imported. +{{< /note >}} + +### Assess Current Azure VM Requirements + +Assess your Azure Virtual Machine using either the Azure Portal or the Azure CLI. Use these methods to gather the CPU, memory, storage, networking, and firewall details needed for migration. + +{{< tabs >}} +{{< tab "Azure Portal" >}} +#### CPU and Memory + +1. In the Azure Portal, open the **Resource groups** page and select the group that contains the VM you want to migrate: + + ![Azure Portal showing a list of Resource Groups.](azure-resource-groups-list.png) + +1. From the list of resources in the group, locate and select the VM you intend to migrate: + + ![Azure Resource Group with a VM listed among its resources.](azure-resource-group-vm-list.png) + +1. On the **VM details** page, expand the **Essentials** section to view your VM's **Size** and specifications (e.g. `Standard B2s (2 vcpus, 4 GiB memory)`): + + ![Azure VM details page showing the Essentials section with the VM size, vCPU count, and memory capacity.](azure-vm-essentials-size-specs.png) + +#### Storage + +4. Return to the list of resources for your Resource Group and select the disk associated with your VM: + + ![Azure Resource Group with a managed disk selected.](azure-vm-disk-selected.png) + +1. The **Properties** section of the disk details page shows the disk’s size and storage type: + + ![Azure disk details page showing disk size and storage type.](azure-disk-properties.png) + + The example Azure disk for this guide has a size of 5 GB. + +#### IP Addresses + +6. The **Essentials** section of the VM details page displays the external IP address for the VM (e.g. `13.91.244.136`). + +#### Network Security Groups and Firewall Rules + +7. Return to the list of resources for your Resource Group and select the network security group resource: + + ![Azure Resource Group with a Network Security Group resource selected.](azure-nsg-resource-selected.png) + +1. A list of inbound and outbound security rules for the network security group is displayed: + + ![Azure Network Security Group rules page showing inbound and outbound rules.](azure-nsg-rules-list.png) +{{< /tab >}} +{{< tab "Azure CLI" >}} +#### CPU and Memory + +1. Use the Azure CLI (`az`) to list all the VMs in a Resource Group, replacing {{< placeholder "RESOURCE_GROUP" >}} with your actual Resource Group name (e.g. `my-resource-group`): + + ```command + az vm list --resource-group {{< placeholder "RESOURCE_GROUP" >}} --output table + ``` + + ```output + Name ResourceGroup Location Zones + ----------- ----------------- ---------- ------- + my-azure-vm my-resource-group westus + ``` + +1. Retrieve the VM size by specifying the {{< placeholder "RESOURCE_GROUP" >}} and {{< placeholder "VM_NAME" >}} (e.g. `my-azure-vm`): + + ```command + az vm show \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --name {{< placeholder "VM_NAME" >}} \ + --query "hardwareProfile.vmSize" + ``` + + ```output + "Standard_B2s" + ``` + +1. Show the specifications for a VM size by replacing {{< placeholder "LOCATION" >}} (e.g. `westus`) and {{< placeholder "VM_SIZE" >}} (e.g. `Standard_B2s`) with the location of your Resource Group and your VM size: + + ```command + az vm list-skus \ + --location {{< placeholder "LOCATION" >}} \ + --resource-type virtualMachines \ + --size {{< placeholder "VM_SIZE" >}} \ + --query "[?name=='{{< placeholder "VM_SIZE" >}}'].{ + Name: name, + vCPUs: capabilities[?name=='vCPUs'] | [0].value, + MemoryGB: capabilities[?name=='MemoryGB'] | [0].value, + OSVhdSizeMB: capabilities[?name=='OSVhdSizeMB'] | [0].value, + MaxDataDisks: capabilities[?name=='MaxDataDiskCount'] | [0].value + }" \ + --output table + ``` + + ```output + Name VCPUs MemoryGB OSVhdSizeMB MaxDataDisks + ------------ ------- ---------- ------------- -------------- + Standard_B2s 2 4 1047552 4 + ``` + +#### Storage + +4. Retrieve the disk details for your VM, replacing {{< placeholder "RESOURCE_GROUP" >}} and {{< placeholder "VM_NAME" >}}: + + ```command + az vm show \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --name {{< placeholder "VM_NAME" >}} \ + --query "storageProfile.osDisk" + ``` + + ```output + { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diffDiskSettings": null, + "diskSizeGb": 5, + "encryptionSettings": null, + "image": null, + "managedDisk": { + "diskEncryptionSet": null, + "id": "/subscriptions/980e30f1-992f-4635-9eb0-1b5fe23ec084/resourceGroups/my-resource-group/providers/Microsoft.Compute/disks/my-azure-vm_disk1_bfb86e561c3a4716b164f82f4e558b8e", + "resourceGroup": "my-resource-group", + "securityProfile": null, + "storageAccountType": "Premium_LRS" + }, + "name": "my-azure-vm_disk1_bfb86e561c3a4716b164f82f4e558b8e", + "osType": "Linux", + "vhd": null, + "writeAcceleratorEnabled": null + } + ``` + + The example Azure disk for this guide has a size of 5 GB. + +#### IP Addresses + +5. Retrieve the name of the network interface, replacing {{< placeholder "RESOURCE_GROUP" >}} and {{< placeholder "VM_NAME" >}}: + + ```command + az vm show \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --name {{< placeholder "VM_NAME" >}} \ + --query "networkProfile.networkInterfaces[0].id" + ``` + + In Azure, resources such as network interfaces have both an ID and a name. The ID has the form of a full path, for example: + + ```output + "/subscriptions/980e30f1-992f-4635-9eb0-1b5fe23ec084/resourceGroups/my-resource-group/providers/Microsoft.Network/networkInterfaces/my-azure-vm930" + ``` + + The {{< placeholder "NETWORK_INTERFACE_NAME" >}} can be inferred through the final part of the path (e.g. `my-azure-vm930`). + +1. Use the resulting {{< placeholder "NETWORK_INTERFACE_NAME" >}} to get the name of the public IP address created by Azure: + + ```command + az network nic show \ + --name {{< placeholder "NETWORK_INTERFACE_NAME" >}} \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --query "ipConfigurations[0].publicIPAddress.id" + ``` + + The {{< placeholder "IP_ADDRESS_NAME" >}} can be inferred through the final part of the path (e.g. `my-azure-vm-ip`): + + ```output + "/subscriptions/980e30f1-992f-4635-9eb0-1b5fe23ec084/resourceGroups/my-resource-group/providers/Microsoft.Network/publicIPAddresses/my-azure-vm-ip" + ``` + +1. Use the resulting {{< placeholder "IP_ADDRESS_NAME" >}} to retrieve the details for this resource, including the actual IP address. + + ```command + az network public-ip show \ + --name {{< placeholder "IP_ADDRESS_NAME" >}} \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --query "ipAddress" + ``` + + ```output + "13.91.244.136" + ``` + +#### Network Security Groups and Firewall Rules + +8. Use the {{< placeholder "RESOURCE_GROUP" >}} and the {{< placeholder "NETWORK_INTERFACE" >}} name obtained from your VM information to obtain the network security group name: + + ```command + az network nic show \ + --name {{< placeholder "NETWORK_INTERFACE" >}} \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --query "networkSecurityGroup.id" + ``` + + The name of the {{< placeholder "NETWORK_SECURITY_GROUP" >}} can be inferred through the final part of the path (e.g. `my-azure-vm-nsg`): + + ```output + "/subscriptions/980e30f1-992f-4635-9eb0-1b5fe23ec084/resourceGroups/my-resource-group/providers/Microsoft.Network/networkSecurityGroups/my-azure-vm-nsg" + ``` + +1. Replace {{< placeholder "NETWORK_SECURITY_GROUP" >}} in the following command for a detailed breakdown of the network security group’s configuration, including ingress/egress ports and firewall settings: + + ```command + az network nsg show \ + --name {{< placeholder "NETWORK_SECURITY_GROUP" >}} \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} + ``` + + ```output + { + "defaultSecurityRules": [ + { + "access": "Allow", + "description": "Allow inbound traffic from all VMs in VNET", + ... + "destinationPortRanges": [], + "direction": "Inbound", + ... + "sourcePortRange": "*", + "sourcePortRanges": [], + }, + { + "access": "Allow", + "description": "Allow inbound traffic from azure load balancer", + ... + "destinationPortRange": "*", + "destinationPortRanges": [], + ... + "sourcePortRange": "*", + "sourcePortRanges": [], + }, + ... + ], + ... + "securityRules": [ + { + "access": "Allow", + ... + "destinationPortRange": "22", + "destinationPortRanges": [], + "direction": "Inbound", + ... + "protocol": "TCP", + ... + "sourcePortRange": "*", + "sourcePortRanges": [], + } + ], + "type": "Microsoft.Network/networkSecurityGroups" + } + ``` +{{< /tab >}} +{{< /tabs >}} + +#### Back up Your Azure VM Disk (Optional) + +Before starting your migration, consider backing up the Azure VM disk in case a restoration is needed in the future. + +{{< tabs >}} +{{< tab "Azure Portal" >}} +1. In the Azure Portal, return to the list of resources for the Resource Group and select the disk associated with your VM. + +1. On the disk details page, click **Create snapshot** and go through the configuration options for the snapshot. + + ![Azure Portal showing the Create Snapshot button on the disk details page.](azure-create-snapshot.png) + +1. Your newly created snapshot can be found on the **Snapshots** page: + + ![Azure Snapshots page showing a list of available disk snapshots.](azure-snapshots-page.png) +{{< /tab >}} +{{< tab "Azure CLI" >}} +1. Use the following `az` command to create a snapshot, replacing {{< placeholder "SNAPSHOT_NAME" >}} with a name of your choosing (e.g. `my-disk-snapshot`): + + ```command + az snapshot create \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --name {{< placeholder "SNAPSHOT_NAME" >}} \ + --source {{< placeholder "DISK_NAME_OR_ID" >}} \ + --location {{< placeholder "LOCATION" >}} + ``` + + For example: + + ```command + az snapshot create \ + --resource-group my-resource-group \ + --name my-disk-snapshot \ + --source my-azure-vm_disk1_bfb86e561c3a4716b164f82f4e558b8e \ + --location westus + ``` + + ```output + { + "creationData": { + "createOption": "Copy", + "sourceResourceId": "/subscriptions/980e30f1-992f-4635-9eb0-1b5fe23ec084/resourceGroups/my-resource-group/providers/Microsoft.Compute/disks/my-azure-vm_disk1_bfb86e561c3a4716b164f82f4e558b8e", + "sourceUniqueId": "bfb86e56-1c3a-4716-b164-f82f4e558b8e" + }, + "diskSizeBytes": 5368709120, + "diskSizeGB": 5, + ... + "location": "westus", + "name": "my-disk-snapshot", + "networkAccessPolicy": "AllowAll", + "osType": "Linux", + "provisioningState": "Succeeded", + ... + } + ``` + +1. List all snapshots for a given resource group: + + ```command + az snapshot list --resource-group {{< placeholder "RESOURCE_GROUP" >}} + ``` + + ```output + [ + { + ... + "diskSizeBytes": 5368709120, + "diskSizeGB": 5, + "location": "westus", + "name": "my-disk-snapshot", + "provisioningState": "Succeeded", + "publicNetworkAccess": "Enabled", + ... + } + ] + ``` +{{< /tab >}} +{{< /tabs >}} + +{{< note >}} +The [cost of Azure snapshots](https://azure.microsoft.com/en-us/pricing/details/managed-disks/#pricing) varies depending on redundancy options (local or zone). +{{< /note >}} + +## Migrating to Akamai Cloud + +Migrating an Azure VM to Akamai Cloud involves the following steps: + +- Export the managed disk from your Azure VM. +- Convert the disk image to raw format and prepare it for import. +- Upload the compressed image to Akamai Cloud. +- Launch a new Linode Compute Instance from the uploaded image. +- Verify and configure the new instance. + +### Export the Azure VM Disk + +Before exporting the disk, you must first stop the virtual machine. + +1. In the Azure Portal, navigate to your VM's detail page and click **Stop**: + + ![Azure Portal showing the Stop button for a VM.](azure-vm-stop-button.png) + +1. Next, go to the **Disks** section for the Azure VM, select the OS disk, and click **Disk Export** under **Settings**: + + ![Azure Portal showing the Disk Export option for a VM disk.](azure-disk-export-button.png) + +1. Azure generates a temporary URL to download the disk as a Virtual Hard Disk (VHD) file. Specify an expiration time for the link then click **Generate URL**: + + ![Azure Disk Export screen with the Generate URL option.](azure-generate-url.png) + +1. To generate the disk export URL from the Azure CLI, run the following command: + + ```command + az disk grant-access \ + --name {{< placeholder "DISK_NAME_OR_ID" >}} \ + --resource-group {{< placeholder "RESOURCE_GROUP" >}} \ + --duration-in-seconds 3600 + ``` + + ```output + { + "accessSAS": "https://md-3rnqkqjjh5nk.z41.blob.storage.azure.net/5zfpv2fgr3wv/abcd?sv=2018-03-28&sr=b&si=8f527a7b-e94d-4e44-b6a9-313d2974197b&sig=u0gKMJ%2BSlWEahBUoMg8%2Bppgi5bU65SotEaYD653YI0I%3D" + } + ``` + +1. Use `azcopy` and the {{< placeholder "GENERATED_URL" >}} to download and save the file to your local machine: + + ```command + azcopy copy "{{< placeholder "GENERATED_URL" >}}" ./azure-download.vhd + ``` + + ```output + ... + Job d62cb212-1b78-6a46-6f32-67fed0d3b112 summary + Elapsed Time (Minutes): 4.3353 + Number of File Transfers: 1 + Number of Folder Property Transfers: 0 + Number of Symlink Transfers: 0 + Total Number of Transfers: 1 + Number of File Transfers Completed: 1 + Number of Folder Transfers Completed: 0 + Number of File Transfers Failed: 0 + Number of Folder Transfers Failed: 0 + Number of File Transfers Skipped: 0 + Number of Folder Transfers Skipped: 0 + Total Number of Bytes Transferred: 32213303808 + Final Job Status: Completed + ``` + + The download depends on your internet connection and the size of the exported disk image. + +### Import and Deploy VM Image on Akamai Cloud + +To provision a Linode using an existing VM image, the image must be in raw format (`.img`) and compressed using `gzip`. + +#### Convert Disk Image to Raw Format + +Linode does not support the VHD format used by Azure. Before importing your VM image, you must convert the `.vhd` file to a raw disk image with an `.img` extension. + +1. Perform the conversion using [`qemu-img convert`](https://qemu-project.gitlab.io/qemu/tools/qemu-img.html#cmdoption-qemu-img-arg-convert): + + ```command + qemu-img convert -f vpc -O raw azure-download.vhd azure-image.raw + ``` + + In this command, `-f` specifies the input format (`vpc`), and `-O` specifies the output format (`raw`). These are followed by the input filename and the desired output filename. + +1. The resulting raw file should be nearly the same size as the original VHD file. Confirm this with the following command: + + ```command + stat -c "%s %n" -- azure-* + ``` + + ```output + 5368430592 azure-image.raw + 5368709632 azure-download.vhd + ``` + +#### Prepare Image File for Import + +Linode requires image files to use the `.img` extension. If your raw image file does not already have this extension, rename it accordingly. + +1. Rename the file to use the `.img` extension: + + ```command + mv azure-image.raw azure-image.img + ``` + +1. Compress the image using `gzip` to reduce its size: + + ```command + gzip azure-image.img + ``` + +1. Confirm the compressed image was created and check its size: + + ```command + du -BM azure-image.img.gz + ``` + + ```output + 1737M azure-image.img.gz + ``` + +#### Upload the Compressed File to Akamai Cloud + +Use the Linode CLI to upload your compressed image file. Replace the filename with your specific `.gz` image, and specify the label, description, and region based on your use case. + +```command +linode-cli image-upload \ + --label "azure-vm-migration" \ + --description "Azure VM Import" \ + --region "us-lax" \ + ./azure-image.img.gz +``` + +```output +┌-----------------------┬-----------┬----------------┐ +│ label │ is_public │ status │ +├-----------------------┼-----------┼----------------┤ +│ azure-vm-migration │ False │ pending_upload │ +└-----------------------┴-----------┴----------------┘ +``` + +The upload process may take several minutes depending on the size of your image and network speed. + +#### Verify the Successful Image Upload + +After uploading the image, verify that is was processed and is available for use. Run the following command to list your private images: + +```command +linode-cli images list --is_public false +``` + +```output +┌------------------┬-----------------------┬-----------┬--------┐ +│ id │ label │ status │ size │ +├------------------┼-----------------------┼-----------┼--------┤ +│ private/30228641 │ azure-vm-migration │ available │ 5120 │ +└------------------┴-----------------------┴-----------┴--------┘ +``` + +Check that the `status` is `available`. If the `status` is `pending`, wait a few minutes and try again. + +You can also monitor the upload status from the **Images** section of the Akamai Cloud Manager: + +![Akamai Cloud Manager showing a private image labeled azure-vm-migration with status available.](linode-cloud-manager-private-image-status-azure.png) + +#### Launch a Linode Compute Instance from the Uploaded Image + +Once your image is available, you can deploy it to a new Linode instance. For this command, provide the ID of your uploaded image (shown in the previous step). Also include the following values: + +- `--label`: A unique label for the instance. +- `--region`: The preferred deployment region. +- `--type`: The type of instance to deploy. +- `--root_pass`: A secure root password for SSH access. + +This example deploys a `g6-standard-2` Linode with 2 vCPUs, 80 GB storage, 4 GB RAM, and a 4,000 Mbps transfer rate. This is a comparable configuration to the original Azure `Standard B2s` VM, which also features 2 vCPUs and 4 GB RAM. + +{{< note >}} +See the [Akamai Cloud pricing page](https://www.linode.com/pricing/#compute-shared) for more details on available instance types and their associated costs. +{{< /note >}} + +```command +linode-cli linodes create \ + --image {{< placeholder "LINODE_IMAGE_ID" >}} \ + --label "migrated-from-azure" \ + --region "us-lax" \ + --type "g6-standard-2" \ + --root_pass "{{< placeholder "ROOT_PASSWORD" >}}" +``` + +```output +┌-----------------------┬--------┬---------------┬--------------┐ +│ label │ region │ type │ status │ +├-----------------------┼--------┼---------------┼--------------┤ +│ migrated-from-azure │ us-lax │ g6-standard-2 │ provisioning │ +└-----------------------┴--------┴---------------┴--------------┘ +``` + +By default, Linode boots instances using its own kernel. To instead boot from the kernel embedded in your imported image: + +1. Open the Akamai Cloud Control Center and choose **Linodes** under **Compute** in the left-hand pane. + +1. Select your Linode instance. + +1. Open the **Configurations** tab at the bottom, then select **Edit**. + + ![Linode dashboard with the Configurations tab selected.](linode-configurations-tab.png) + +1. Under **Boot Settings**, select **Direct Disk** as the kernel option. + + ![Linode configuration editor showing Direct Disk selected under Boot Settings.](linode-select-direct-disk-kernel.png) + +1. Click **Save Changes**, then **Reboot** your Linode. + + ![Linode interface showing the Reboot button after saving configuration changes.](linode-reboot-after-config-save.png) + +After several minutes, your Linode instance should be running using the image exported from your Azure VM. + +### Configure and Validate the Linode Instance + +Migrating using a disk image exported from your Azure VM ensures that the operating system and all installed software and services are preserved on the newly provisioned Linode. This reduces the time needed to reconfigure the Linode instance to match the original VM. + +However, you must still configure the Linode's networking to align with your workload. Refer to the configuration details from your original Azure VM and apply them to your Linode as appropriate: + +- [IP Addresses](https://techdocs.akamai.com/cloud-computing/docs/managing-ip-addresses-on-a-compute-instance) +- [Firewall Rules](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-cloud-firewalls) +- [Load Balancing](https://techdocs.akamai.com/cloud-computing/docs/nodebalancer) +- [DNS](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-dns-manager) + +Linode does not have a direct equivalent to Azure Network Security Groups. However, you can still implement a firewall with rules to control traffic. Options include: + +- [Akamai Cloud Firewall](https://techdocs.akamai.com/cloud-computing/docs/cloud-firewall) to set up inbound and outbound rules through the Akamai Cloud Manager, the Linode CLI, or API. +- [`iptables`](/docs/guides/control-network-traffic-with-iptables/) or [`ufw`](/docs/guides/configure-firewall-with-ufw/) to manage the Linux kernel firewall (Netfilter). + +To replicate [Azure Application Gateway](https://learn.microsoft.com/en-us/azure/application-gateway/overview), use Akamai Cloud's [NodeBalancers](https://www.linode.com/products/nodebalancers/) to distribute traffic across multiple Linode instances. + +If you used Azure DNS to route traffic to your Azure VM, you need to update your DNS records to route traffic to your new Linode instance instead. This may involve pointing your domain nameservers to Akamai Cloud and creating DNS rules within the Akamai Cloud Manager. + +After completing your configurations, test your Linode instance to verify that the migration was successful. Validation steps may include: + +- **Check Running Services**: Confirm that all critical services (e.g. web servers, databases, and application processes) are running as expected and configured to start on boot. +- **Test Application Functionality**: Access your applications through their web interface or API endpoints to confirm that they behave as expected, including core functionality and error handling. +- **Inspect Resource Utilization**: Monitor the Linode's CPU, memory, and disk usage to ensure the system performs within acceptable thresholds post-migration. +- **Validate DNS Configuration**: Ensure that any DNS changes are propagating correctly, pointing to your Linode instance, and resolving to the expected IP addresses. +- **Check External Connectivity**: Verify that the Linode can access any required external resources (e.g. third-party APIs, databases, or storage) and that outbound requests succeed. +- **Review Logs**: Examine system and application logs for errors or warnings that might indicate migration-related issues. +- **Backup and Snapshot Functionality**: To safeguard your data post migration, confirm that backups and snapshots can be created successfully. +- **Verify Externally Attached Storage**: Ensure that any additional storage volumes, block devices, or network-attached storage are properly mounted and accessible. Check `/etc/fstab` entries and update disk mappings as needed. + +## Additional Considerations + +### Cost Management + +Review the pricing for your current Azure VM instance, including [compute](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/windows/), [storage](https://azure.microsoft.com/en-ca/pricing/details/managed-disks/), and [bandwidth](https://azure.microsoft.com/en-us/pricing/details/bandwidth/). Compare those costs with the [Akamai Cloud pricing plans](https://www.linode.com/pricing/) using [Akamai’s Cloud Computing Calculator](https://www.linode.com/cloud-computing-calculator/) to estimate your usage. + +### Data Consistency and Accuracy + +After importing your image and launching your Linode, verify that all expected files, configurations, and application data are intact. Verification steps may include: + +- **Generate and Compare File Checksums**: Use tools like `md5sum` to generate checksums of both the source VM and your Linode. Ensure the checksums match to confirm data integrity. +- **Count Files and Directories**: Use commands like `find` or `ls` to count the number of files and directories in key locations (e.g. `find /path -type f | wc -l`). Compare these counts between the source VM and your Linode to identify any discrepancies. +- **Check Application Logs and Settings**: Compare configuration files, environment variables, and application logs between the source and your Linode to confirm they are identical (or appropriately modified for the new environment). Common locations to review may include: + + | Application | Configuration | Location | + |-----------------------|---------------------------|--------------------------------| + | **Apache Web Server** | Main | `/etc/apache2/apache2.conf` | + | | Virtual hosts | `/etc/apache2/sites-available` | + | | | `/etc/apache2/sites-enabled` | + | **NGINX Web Server** | Main | `/etc/nginx/nginx.conf` | + | | Virtual hosts | `/etc/nginx/sites-available` | + | | | `/etc/nginx/sites-enabled` | + | **Cron** | Application | `/etc/cron.d` | + | | System-wide `cron` jobs | `/etc/crontab` | + | | User-specific `cron` jobs | `/var/spool/cron/crontabs` | + | **MySQL/MariaDB** | Main | `/etc/mysql` | + | **PostgreSQL** | Main | `/etc/postgresql` | + | **SSH** | Main | `/etc/ssh/sshd_config` | + | **Networking** | Hostname | `/etc/hostname` | + | | Hosts file | `/etc/hosts` | + | **Rsyslog** | Main | `/etc/rsyslog.conf` | + +- **Review Symbolic Links and Permissions**: Use CLI tools and commands to confirm that symbolic links and file permissions on your Linode match those on the source VM. Examples include: + + | Description | Command | + |---------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| + | List all symbolic links in folder (recursive). | `ls -Rla /path/to/folder \| grep "\->"` | + | Calculate md5 hash for all files in a folder, then sort by filename and write to file. Then, compare files from both VMs using `diff`. | `find /path/to/folder/ -type f -exec md5sum {} + \| sort -k 2 > hashes.txt` | + | Write to file the folder contents (recursive) with permissions, owner name, and group name. Then, compare permissions files from both VMs using `diff`. | `tree /path/to/folder -fpuig > permissions.txt` | + +After deploying your Linode, confirm that the configurations (network settings, environment variables, and application dependencies) match the source VM to avoid runtime issues. + +### Security and Access Controls + +[Azure roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles) govern instance access. To migrate these roles and permissions to Akamai Cloud: + +- Create Linode API tokens and fine-tune user permissions. +- Reproduce Azure network security group policy rules in the Akamai Cloud Firewall or existing system firewall. +- Properly configure SSH keys and disable root login if not required. + +### Alternative Migration Options + +If exporting a disk image is not viable due to provider restrictions or image size constraints, consider these alternative migration options: + +- **Data-only Transfer**: Provision a Linode with resource levels comparable to your source VM, then use [rclone](https://rclone.org/) to move all data from your source VM to your new Linode. +- **Infrastructure-as-Code (IaC)**: Replicate your source VM on Linode using tools like [Ansible](https://docs.ansible.com/ansible/latest/index.html), [Terraform](https://www.terraform.io/), [Chef](https://www.chef.io/products/chef-infra), and [Puppet](https://www.puppet.com/why-puppet/use-cases/continuous-configuration-automation). These tools can help replicate server configurations, deploy applications, and ensure consistency. +- **Containerization**: Containerize workloads and deploy them to a [Linode Kubernetes Engine (LKE)](https://techdocs.akamai.com/cloud-computing/docs/linode-kubernetes-engine) cluster, eliminating the need to migrate the VM entirely. + +## Resources + +Azure: +- [Azure CLI (`az`) Documentation](https://learn.microsoft.com/en-us/cli/azure/) +- Downloading a VHD from Azure + - [Linux](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/download-vhd) + - [Windows](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/download-vhd?tabs=azure-portal) +- [Troubleshooting backup failures on Azure virtual machines](https://learn.microsoft.com/en-us/azure/backup/backup-azure-vms-troubleshoot) + +Akamai Cloud: +- [Linode CLI and Object Storage](https://techdocs.akamai.com/cloud-computing/docs/using-the-linode-cli-with-object-storage) +- [Uploading an image](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) +- [Deploying an Image](https://techdocs.akamai.com/cloud-computing/docs/deploy-an-image-to-a-new-compute-instance) + +Other helpful utilities: +- [QEMU Disk Imaging Utility](https://www.qemu.org/download/) +- [rclone](https://rclone.org/) +- [Shrinking images on Linux](https://softwarebakery.com//shrinking-images-on-linux) \ No newline at end of file diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-azure.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-azure.png new file mode 100644 index 00000000000..4f8fe88b93b Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-azure.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-configurations-tab.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-configurations-tab.png new file mode 100644 index 00000000000..fe3483e02b3 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-configurations-tab.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-reboot-after-config-save.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-reboot-after-config-save.png new file mode 100644 index 00000000000..bcf865b3b27 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-reboot-after-config-save.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png new file mode 100644 index 00000000000..817d572efff Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-azure-virtual-machine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-create-image-menu.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-create-image-menu.png new file mode 100644 index 00000000000..b721f3e8c35 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-create-image-menu.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ebs-create-snapshot.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ebs-create-snapshot.png new file mode 100644 index 00000000000..ddc622e8237 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ebs-create-snapshot.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-details.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-details.png new file mode 100644 index 00000000000..01633c9d6e9 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-details.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-ip-addresses.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-ip-addresses.png new file mode 100644 index 00000000000..d619f3a2f64 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instance-ip-addresses.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instances-page.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instances-page.png new file mode 100644 index 00000000000..97ce58522c0 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-instances-page.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-security-groups.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-security-groups.png new file mode 100644 index 00000000000..dffb1f9f50f Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-security-groups.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-storage-tab.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-storage-tab.png new file mode 100644 index 00000000000..66171e7f96b Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-storage-tab.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-volume-details.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-volume-details.png new file mode 100644 index 00000000000..0ab32b2015d Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-ec2-volume-details.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-export-image-status.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-export-image-status.png new file mode 100644 index 00000000000..5429ab756c0 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-export-image-status.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-s3-bucket-policy-editor.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-s3-bucket-policy-editor.png new file mode 100644 index 00000000000..7f87b5f2673 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/aws-s3-bucket-policy-editor.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/index.md b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/index.md new file mode 100644 index 00000000000..21dde7db53e --- /dev/null +++ b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/index.md @@ -0,0 +1,766 @@ +--- +slug: transfer-vm-from-aws-ec2-to-akamai-using-disk-images +title: "Transfer VM From AWS EC2 to Akamai Using Disk Images" +description: "Two to three sentences describing your guide." +authors: ["Linode"] +contributors: ["Linode"] +published: 2025-05-28 +keywords: ['list','of','keywords','and key phrases'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +external_resources: +- '[Link Title 1](http://www.example.com)' +- '[Link Title 2](http://www.example.net)' +--- + +In modern cloud computing, virtual machine (VM) migration is a process that enables organizations to transition workloads between cloud platforms to optimize costs, improve performance, or enhance flexibility. By migrating VMs, organizations can select the capabilities of various cloud providers that best satisfy their business needs. + +This guide focuses on migrating a VM from Amazon Web Services (AWS) Elastic Compute Cloud (EC2) to Akamai Cloud using disk images suggests how to plan, execute, and validate the migration. + +## Before You Begin + +1. Log in to your [Akamai Cloud](https://www.linode.com/cfe) account to prepare the destination environment. + +1. Create a [Linode API token (personal access token)](/docs/products/platform/accounts/guides/manage-api-tokens/) so you can authenticate with the Linode CLI. + +1. Install and configure the [Linode CLI](/docs/products/tools/cli/guides/install/) on your local system. + +1. You must also have access to an AWS account with sufficient permissions to manage EC2 instances, including the ability to create and export AMIs. + +1. Install and configure the [AWS CLI](https://aws.amazon.com/cli/) to interact with your EC2 instances. + +1. Install [`jq`](https://jqlang.github.io/jq/download/), a lightweight tool used to parse JSON output from the CLIs. + +{{< note >}} +This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you’re not familiar with the `sudo` command, see the [Users and Groups](/docs/guides/linux-users-and-groups/) guide. +{{< /note >}} + +## Preparing Your AWS EC2 Environment for Migration + +Before migrating, review your AWS EC2 instance configuration to ensure compatibility with Akamai Cloud. Note any instance-specific dependencies, such as storage size, image type, or hardware requirements, that may impact the transition. + +Record the configuration details of your EC2 instance to help choose an [Akamai Cloud plan](https://www.linode.com/pricing/#compute-shared) that matches your resource needs after migration. + +{{< note >}} +[Images imported into Akamai Cloud](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) must be smaller than 6 GB unzipped or 5 GB zipped. Images exceeding the size limit are rejected during upload and not imported. +{{< /note >}} + +### Assess Current EC2 Instance Specifications + +Assess your EC2 instance using either the AWS Console or the AWS CLI. Use these methods to gather the CPU, memory, storage, networking, and firewall details needed for migration. + +{{< tabs >}} +{{< tab "AWS Console" >}} +#### CPU and Memory + +1. In the AWS Console, open the **EC2** service and navigate to the **Instances** page: + + ![AWS EC2 Instances page showing a list of virtual machines.](aws-ec2-instances-page.png) + +1. Locate the EC2 instance you intend to migrate: + + ![EC2 instance details showing instance ID and instance type.](aws-ec2-instance-details.png) + + Note the **Instance ID** (e.g. `i-0e1dc0292b0ae7293`) and the **Instance type** (e.g. `t2.medium`). + +#### Storage + +3. Navigate to the **Storage** tab for your EC2 instance: + + ![AWS EC2 instance details page with the Storage tab selected.](aws-ec2-storage-tab.png) + +1. Select the listed volume to view your instance's attached storage volume type and size: + + ![EBS volume details showing volume type and size.](aws-ec2-volume-details.png) + + In this example, the attached storage volume is the `gp3` type with a size of 2 GB. + +#### IP Addresses + +5. Your instance's public and private IP addresses are listed on the instance summary page: + + ![AWS EC2 instance summary showing public and private IP addresses.](aws-ec2-instance-ip-addresses.png) + +#### Security Groups and Firewall Rules + +6. Navigate to the **Security** tab of your EC2 instance to view it's associated security groups and firewall rules: + + ![AWS EC2 Security tab showing associated security groups and firewall rules.](aws-ec2-security-groups.png) +{{< /tab >}} +{{< tab "AWS CLI" >}} +#### CPU and Memory + +1. Use the AWS CLI (`aws`) to retrieve the CPU and memory specifications of your EC2 instance, replacing {{< placeholder "INSTANCE_TYPE" >}} with your actual instance type (e.g. `t2.medium`): + + ```command + aws ec2 describe-instance-types --instance-types={{< placeholder "INSTANCE_TYPE" >}} \ + | jq '.InstanceTypes[0] | {VCpuInfo, MemoryInfo}' + ``` + + ```output + { + "VCpuInfo": { + "DefaultVCpus": 2, + "DefaultCores": 2, + "DefaultThreadsPerCore": 1 + }, + "MemoryInfo": { + "SizeInMiB": 4096 + } + } + ``` + +#### Storage + +2. Retrieve volume size and type for your EC2 instance, replacing {{< placeholder "INSTANCE_ID" >}} with your actual instance ID (e.g. `i-0e1dc0292b0ae7293`): + + ```command + aws ec2 describe-volumes \ + --filters "Name=attachment.instance-id,Values={{< placeholder "INSTANCE_ID" >}}" \ + | jq '.Volumes[0] | {Size, VolumeType}' + ``` + + ```output + { + "Size": 2, + "VolumeType": "gp3" + } + ``` + +#### IP Addresses + +3. Retrieve the public and private IP addresses of your EC2 instance, replacing {{< placeholder "INSTANCE_ID" >}} as needed: + + ```command + aws ec2 describe-instances + --instance-ids {{< placeholder "INSTANCE_ID" >}} \ + | jq \ + '.Reservations[0].Instances[0] | {PublicIpAddress,PrivateIpAddress}' + ``` + + ```output + { + "PublicIpAddress": "54.219.166.73", + "PrivateIpAddress": "172.31.5.242" + } + ``` + +#### Security Groups and Firewall Rules + +4. List the security groups associated with your EC2 instance, replace {{< placeholder "INSTANCE_ID" >}}: + + ```command + aws ec2 describe-instances \ + --instance-ids {{< placeholder "INSTANCE_ID" >}} \ + | jq '.Reservations[0].Instances[0].SecurityGroups' + ``` + + ```output + [ + { + "GroupName": "default", + "GroupId": "sg-05bb8599e5070fc89" + } + ] + ``` + +1. List the rule IDs in the security group by replacing {{< placeholder "SECURITY_GROUP_ID" >}} with your `GroupId` from the previous output (e.g. `sg-05bb8599e5070fc89`): + + ```command + aws ec2 describe-security-group-rules \ + --filters "Name=group-id,Values={{< placeholder "SECURITY_GROUP_ID" >}}" \ + | jq '.SecurityGroupRules[] | {SecurityGroupRuleId, IsEgress, IpProtocol, FromPort, ToPort, CidrIpv4}' + ``` + + ```output + { + "SecurityGroupRules": [ + { + "SecurityGroupRuleId": "sgr-0eb2e5aee98524d46", + "GroupId": "sg-05bb8599e5070fc89", + "GroupOwnerId": "153917289119", + "IsEgress": false, + "IpProtocol": "tcp", + "FromPort": 443, + "ToPort": 443, + "CidrIpv4": "0.0.0.0/0", + "Tags": [] + }, + { + "SecurityGroupRuleId": "sgr-0936993e811c9ea8d", + "GroupId": "sg-05bb8599e5070fc89", + "GroupOwnerId": "153917289119", + "IsEgress": false, + "IpProtocol": "tcp", + "FromPort": 22, + "ToPort": 22, + "CidrIpv4": "0.0.0.0/0", + "Tags": [] + }, + { + "SecurityGroupRuleId": "sgr-0fa434147d85e6031", + "GroupId": "sg-05bb8599e5070fc89", + "GroupOwnerId": "153917289119", + "IsEgress": false, + "IpProtocol": "tcp", + "FromPort": 80, + "ToPort": 80, + "CidrIpv4": "0.0.0.0/0", + "Tags": [] + }, + { + "SecurityGroupRuleId": "sgr-029ee55aa41939b76", + "GroupId": "sg-05bb8599e5070fc89", + "GroupOwnerId": "153917289119", + "IsEgress": true, + "IpProtocol": "-1", + "FromPort": -1, + "ToPort": -1, + "CidrIpv4": "0.0.0.0/0", + "Tags": [] + } + ] + } + ``` +{{< /tab >}} +{{< /tabs >}} + +{{< note title="Other Networking-Related Configurations" >}} +Determine if your EC2 instance is associated with any load balancer, custom DNS records, or other networking components. Record this information, as it may affect how you provision your Linode instance and configure its networking resources. +{{< /note >}} + +### Back up Your Data on AWS EC2 + +Creating a comprehensive backup of your EC2 instance ensures you can restore your environment in case of unexpected issues during the migration. With a backup in place, migrating to Akamai Cloud becomes safer and more predictable. + +AWS provides two approaches to create a backup of your EC2 instance: + +- **Create a Snapshot**: A snapshot captures a point-in-time copy of your attached EBS volume: + + 1. In the AWS Console, navigate to the details page for your EBS volume. + + 1. Select the volume attached to your EC2 instance. + + 1. Click **Actions** then choose **Create Snapshot**. + + ![AWS EBS volume actions menu with "Create Snapshot" highlighted.](aws-ebs-create-snapshot.png) + +- **Create an Amazon Machine Image (AMI)**: An AMI includes the full state of your EC2 instance, including the OS, applications, and configuration. You can import this image to Akamai Cloud when migrating a VM, which is the approach this guide demonstrates. + +{{< note >}} +Backups on AWS may incur costs. Refer to [Amazon EC2 pricing](https://aws.amazon.com/ec2/pricing/on-demand/) for more information. +{{< /note >}} + +## Migrating to Akamai Cloud + +Migrating an AWS EC2 instance to Akamai Cloud involves the following steps: + +- Export the instance image by creating an Amazon Machine Image (AMI). +- Set up the necessary permissions and export the AMI to an S3 bucket. +- Download the image file from S3 and prepare it for import. +- Upload the compressed image to Akamai Cloud. +- Launch a new Linode Compute Instance from the uploaded image. +- Verify and configure the new instance. + +### Export Your AWS EC2 Environment + +#### Create an AMI + +To begin the migration process, create an Amazon Machine Image (AMI) that captures your EC2 instance's disk and configuration. + +1. From the EC2 instance summary page in the AWS Management Console, navigate to **Instance state > Image and templates > Create image**: + + ![AWS EC2 console showing the Create image option in the Instance state menu.](aws-create-image-menu.png) + +1. Provide a name and optional description for your image, then click **Create image**: + +You can also perform this action using the AWS CLI: + +1. Run the following command to create an AMI: + + ```command + aws ec2 create-image \ + --instance-id i-0e1dc0292b0ae7293 \ + --name "ec2-pre-migration-image" \ + --description "EC2 instance prior to Linode migration" \ + --no-reboot + ``` + + The `--no-reboot` flag is optional and prevents the instance from restarting during the image creation process. Omit this flag if you prefer a clean shutdown to ensure disk consistency. + + The output includes the ID of the newly created image: + + ```output + { + "ImageId": "ami-0b5823d737dcd831a" + } + ``` + +1. Use the `describe-images` command to list existing images and monitor image creation status: + + ```command + aws ec2 describe-images --owner self + ``` + + Look for the `State` field, which should change from `pending` to `available`: + + ```output + { + "Images": [ + { + ... + "ImageId": "ami-0b5823d737dcd831a", + "ImageType": "machine", + "Public": false, + "PlatformDetails": "Linux/UNIX", + "UsageOperation": "RunInstances", + "State": "available", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/xvda", + "Ebs": { + "DeleteOnTermination": true, + "Iops": 3000, + "SnapshotId": "snap-0cfa25763b370690d", + "VolumeSize": 2, + "VolumeType": "gp3", + "Throughput": 125, + "Encrypted": false + } + } + ], + "Description": "EC2 instance prior to Linode migration", + "EnaSupport": true, + "Hypervisor": "xen", + "Name": "ec2-pre-migration-image", + "RootDeviceName": "/dev/xvda", + "RootDeviceType": "ebs", + ... + "SourceInstanceId": "i-0e1dc0292b0ae7293" + } + ] + } + ``` + +#### Create S3 Bucket + +Once the AMI is available, you can export it as a virtual machine image. The [`export-image`](https://docs.aws.amazon.com/cli/latest/reference/ec2/export-image.html) command supports the following disk formats: + +- **RAW** (`.img`): The required format for Akamai Cloud. +- **VMDK**: The required format for VMWare. +- **VHD**: The required format for Hyper-V. + +The exported image must be stored in an Amazon S3 bucket. Before you can export it, you must create an S3 bucket: + +```command +aws s3 mb s3://ec2-backup-images-for-migration +``` + +```output +make_bucket: ec2-backup-images-for-migration +``` + +{{< note >}} +Creating a new S3 bucket may incur additional AWS charges. Refer to the [Amazon S3 pricing page](https://aws.amazon.com/s3/pricing/) for details. +{{< /note >}} + +#### Set up Permissions for Exporting AMI to S3 + +To allow the EC2 service to export your AMI to an S3 bucket, you must first grant the appropriate permissions. + +1. Paste the following policy into the **Permissions > Bucket Policy** section of your S3 bucket in the AWS Console, replacing {{< placeholder "BUCKET_NAME" >}} and {{< placeholder "AWS_ACCOUNT_ID" >}} with the appropriate values: + + ```file {title="bucket-policy.json"} + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { "Service": "vmie.amazonaws.com" }, + "Action": "s3:PutObject", + "Resource": "arn:aws:s3:::{{< placeholder "BUCKET_NAME" >}}/*", + "Condition": { + "StringEquals": { "aws:SourceAccount": "{{< placeholder "AWS_ACCOUNT_ID" >}}" } + } + } + ] + } + ``` + + ![AWS S3 bucket policy editor showing a policy granting vmie.amazonaws.com permission to write to the bucket.](aws-s3-bucket-policy-editor.png) + +1. AWS [requires the `vmimport` role](https://docs.aws.amazon.com/vm-import/latest/userguide/required-permissions.html) to export AMIs. If this role does not exist in your account, you must create it manually. Create a trust policy JSON file (e.g. `trust-policy.json`): + + ```command + nano trust-policy.json + ``` + + Give the file the following contents: + + ```file + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { "Service": "vmie.amazonaws.com" }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals":{ + "sts:Externalid": "vmimport" + } + } + } + ] + } + ``` + + When done, press CTRL+X, followed by Y then Enter to save the file and exit `nano`. + +1. Assuming the file is saved in your current user's home directory, run the following command to create the `vmimport` role: + + ```command + aws iam create-role \ + --role-name vmimport \ + --assume-role-policy-document file:///home/user/trust-policy.json + ``` + +1. Create a permissions policy file (e.g. `permissions-policy.json`): + + ```command + nano permissions-policy.json + ``` + + Give the file the following contents, replacing {{< placeholder "BUCKET_NAME" >}} with the appropriate value: + + ```file {title="permissions-policy.json"} + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetBucketLocation", + "s3:GetObject", + "s3:PutObject" + ], + "Resource": "arn:aws:s3:::{{< placeholder "BUCKET_NAME" >}}/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CancelConversionTask", + "ec2:CancelExportTask", + "ec2:CreateImage", + "ec2:CreateInstanceExportTask", + "ec2:CreateTags", + "ec2:Describe*", + "ec2:ExportImage", + "ec2:ImportInstance", + "ec2:ImportVolume", + "ec2:StartInstances", + "ec2:StopInstances", + "ec2:TerminateInstances", + "ec2:ImportImage", + "ec2:ImportSnapshot", + "ec2:ModifySnapshotAttribute", + "ec2:CopySnapshot", + "ec2:RegisterImage", + "ec2:CancelImportTask" + ], + "Resource": "*" + } + ] + } + ``` + + When done, press CTRL+X, followed by Y then Enter to save the file and exit `nano`. + +1. Attach this policy to the newly created `vmimport` role: + + ```command + aws iam put-role-policy \ + --role-name vmimport \ + --policy-name vmimport-permissions \ + --policy-document file:///home/user/permissions-policy.json + ``` + +#### Export AMI to S3 + +1. Export your AMI as a RAW disk image to your S3 bucket, replacing {{< placeholder "AMI_ID" >}} and {{< placeholder "BUCKET_NAME" >}} with your actual values: + + ```command + aws ec2 export-image \ + --image-id {{< placeholder "AMI_ID" >}} \ + --disk-image-format RAW \ + --s3-export-location \ + S3Bucket={{< placeholder "BUCKET_NAME" >}},S3Prefix=exports/ + ``` + + ```output + { + "DiskImageFormat": "RAW", + "ExportImageTaskId": "export-ami-9dadaf55b2b57810t", + "ImageId": "ami-0b5823d737dcd831a", + "Progress": "0", + "S3ExportLocation": { + "S3Bucket": "ec2-backup-images-for-migration", + "S3Prefix": "exports" + }, + "Status": "active", + "StatusMessage": "validating" + } + ``` + +1. The export process may take several minutes or more. Run the following command to check the status, replacing {{< placeholder "EXPORT_IMAGE_TASK_ID" >}} with the result of the previous command (e.g. `export-ami-9dadaf55b2b57810t`): + + ```command + aws ec2 describe-export-tasks \ + --export-task-ids {{< placeholder "EXPORT_IMAGE_TASK_ID" >}} + ``` + + ```output + { + "ExportTasks": [ + { + "ExportTaskId": "export-ami-9dadaf55b2b57810t", + "ExportToS3Task": { + "DiskImageFormat": "RAW", + "S3Bucket": "ec2-backup-images-for-migration" + }, + "InstanceExportDetails": {}, + "State": "active" + } + ] + } + ``` + +When the `State` value changes to `completed`, the disk image is ready for download from your S3 bucket. + +![AWS EC2 Export Tasks page showing an AMI export task in progress with status "active".](aws-export-image-status.png) + +#### Download Image File from S3 + +1. Download the exported `.raw` disk image from your S3 bucket to your local machine. You can do this using either the AWS Console or the following AWS CLI command: + + ```command + aws s3 cp s3://{{< placeholder "BUCKET_NAME" >}}/exports/{{< placeholder "IMAGE_FILE" >}} ./ + ``` + +1. After the download completes, verify the presence and size of the image file: + + ```command + ls -h *.raw + ``` + + ```output + -rw-rw-r-- 2.0G export-ami-9dadaf55b2b57810t.raw + ``` + +### Import and Deploy VM Image on Akamai Cloud + +To provision a Linode by importing an existing VM image, ensure the image is in the proper format and compressed with `gzip`. + +#### Prepare Image File for Import + +The export task from AWS above creates a disk image with the `.raw` file extension. Linode requires an image file with an `.img` extension. + +1. Rename the file to use the `.img` extension: + + ```command + mv export-ami-9dadaf55b2b57810t.raw export-ami-9dadaf55b2b57810t.img + ``` + +1. Compress the image using `gzip` to reduce its size: + + ```command + gzip export-ami-9dadaf55b2b57810t.img + ``` + +1. Confirm the compressed image was created and check its size: + + ```command + du -BM export-ami-9dadaf55b2b57810t.img.gz + ``` + + ```output + 422M export-ami-9dadaf55b2b57810t.img.gz + ``` + +#### Upload the Compressed File to Akamai Cloud + +Use the Linode CLI to upload your compressed image file. Replace the filename with your specific `.gz` image, and specify the label, description, and region based on your use case. + +```command +linode-cli image-upload \ + --label "aws-ec2-migration-ami" \ + --description "AWS EC2 Import" \ + --region "us-lax" \ + ./export-ami-9dadaf55b2b57810t.img.gz +``` + +```output +┌-----------------------┬-----------┬----------------┐ +│ label │ is_public │ status │ +├-----------------------┼-----------┼----------------┤ +│ aws-ec2-migration-ami │ False │ pending_upload │ +└-----------------------┴-----------┴----------------┘ +``` + +The upload process may take several minutes depending on the size of your image and network speed. + +#### Verify the Successful Image Upload + +After uploading the image, verify that it was processed and is available for use. Run the following command to list your private images: + +```command +linode-cli images list --is_public false +``` + +```output +┌------------------┬-----------------------┬-----------┬--------┐ +│ id │ label │ status │ size │ +├------------------┼-----------------------┼-----------┼--------┤ +│ private/29293519 │ aws-ec2-migration-ami │ available │ 2048 │ +└------------------┴-----------------------┴-----------┴--------┘ +``` + +Check that the `status` is `available`. If the `status` is `pending`, wait a few minutes and try again. + +#### Launch a Linode Compute Instance from the Uploaded Image + +Once your image is available, you can deploy it to a new Linode instance. For this command, provide the ID of your uploaded image (shown in the previous step). Also include the following values: + +- `--label`: A unique label for the instance. +- `--region`: The preferred deployment region. +- `--type`: The type of instance to deploy. +- `--root_pass`: A secure root password for SSH access. + +This example deploys a `g6-standard-2` Linode, which provides 2 vCPUs, 80 GB storage, 4 GB RAM, and a 4,000 Mbps transfer rate. This is a comparable configuration to the original AWS EC2 `t2.medium` instance, which also features two vCPUs and 4 GB RAM. + +{{< note >}} +See the [Akamai Cloud pricing page](https://www.linode.com/pricing/#compute-shared) for more details on available instance types and their associated costs. +{{< /note >}} + +```command +linode-cli linodes create \ + --image {{< placeholder "IMAGE_ID" >}} \ + --label "migrated-from-aws-ec2" \ + --region "us-lax" \ + --type "g6-standard-2" \ + --root_pass "{{< placeholder "ROOT_PASSWORD" >}}" +``` + +```output +┌-----------------------┬--------┬---------------┬--------------┐ +│ label │ region │ type │ status │ +├-----------------------┼--------┼---------------┼--------------┤ +│ migrated-from-aws-ec2 │ us-lax │ g6-standard-2 │ provisioning │ +└-----------------------┴--------┴---------------┴--------------┘ +``` + +After several minutes, your Linode instance should be running using the image exported from your AWS EC2 instance. + +![Akamai Cloud Manager showing a new Compute Instance being created from a custom image.](linode-create-instance-from-uploaded-image.png) + +### Configure and Validate the Linode Instance + +Migrating using an AMI that captures your EC2 instance and volumes ensures that the operating system and all installed software and services are preserved on the newly provisioned Linode. This reduces the time needed to reconfigure the Linode instance to match the original VM. + +However, you must still configure the Linode's networking to align with your workload. Refer to the configuration details of your original EC2 instance and apply them to your Linode as appropriate: + +- [IP Addresses](https://techdocs.akamai.com/cloud-computing/docs/managing-ip-addresses-on-a-compute-instance) +- [Firewall Rules](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-cloud-firewalls) +- [Load Balancing](https://techdocs.akamai.com/cloud-computing/docs/nodebalancer) +- [DNS](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-dns-manager) + +Linode does not have a direct equivalent to AWS security groups. However, you can still implement a firewall with rules to control traffic. Options include: + +- [Akamai Cloud Firewall](https://techdocs.akamai.com/cloud-computing/docs/cloud-firewall) to set up inbound and outbound rules through the Akamai Cloud Manager, the Linode CLI, or API. +- [`iptables`](/docs/guides/control-network-traffic-with-iptables/) or [`ufw`](/docs/guides/configure-firewall-with-ufw/) to manage the Linux kernel firewall (Netfilter). + +To replicate the functionality of AWS Application Load Balancers (ALB), use Akamai Cloud's [NodeBalancers](https://www.linode.com/products/nodebalancers/) to distribute traffic across multiple Linode instances. + +If you used AWS Route 53 to route traffic to your EC2 instance, you need to update your DNS records to route traffic to your new Linode instance instead. This may involve pointing your domain's nameservers to Akamai Cloud and creating DNS rules within the Akamai Cloud Manager. + +After completing your configurations, test your Linode instance to ensure that the migration was successful. Validation steps may include: + +- **Check Running Services**: Confirm that all critical services (e.g. web servers, databases, and application processes) are running as expected and configured to start on boot. +- **Test Application Functionality**: Access your applications through their web interface or API endpoints to confirm that they behave as expected, including core functionality and error handling. +- **Inspect Resource Utilization**: Monitor the Linode's CPU, memory, and disk usage to ensure the system performs within acceptable thresholds post-migration. +- **Validate DNS Configuration**: Ensure that any DNS changes are propagating correctly, pointing to your Linode instance, and resolving to the expected IP addresses. +- **Check External Connectivity**: Verify that the Linode can access any required external resources (e.g. third-party APIs, databases, or storage) and that outbound requests succeed. +- **Review Logs**: Examine system and application logs for errors or warnings that might indicate migration-related issues. +- **Backup and Snapshot Functionality**: To safeguard your data post migration, confirm that backups and snapshots can be created successfully. +- **Verify Externally Attached Storage**: Ensure that any additional storage volumes, block devices, or network-attached storage are properly mounted and accessible. Check `/etc/fstab` entries and update disk mappings as needed. + +## Additional Considerations + +### Cost Management + +Review the pricing for your current AWS EC2 instance, including [compute](https://aws.amazon.com/ec2/pricing/on-demand/#On-Demand_Pricing), [storage](https://aws.amazon.com/ebs/pricing/), and [bandwidth](https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer). Compare those costs with the [Akamai Cloud pricing plans](https://www.linode.com/pricing/) using [Akamai’s Cloud Computing Calculator](https://www.linode.com/cloud-computing-calculator/) to estimate your usage. + +### Data Consistency and Accuracy + +After importing your image and launching your Linode, verify that all expected files, configurations, and application data are intact. Verification steps may include: + +- **Generate and Compare File Checksums**: Use tools like `md5sum` to generate checksums of both the source VM and your Linode. Ensure the checksums match to confirm data integrity. +- **Count Files and Directories**: Use commands like `find` or `ls` to count the number of files and directories in key locations (e.g. `find /path -type f | wc -l`). Compare these counts between the source VM and your Linode to identify any discrepancies. +- **Check Application Logs and Settings**: Compare configuration files, environment variables, and application logs between the source VM and your Linode to confirm they are identical (or appropriately modified for the new environment). Common locations to review may include: + + | Application | Configuration | Location | + |-----------------------|---------------------------|--------------------------------| + | **Apache Web Server** | Main | `/etc/apache2/apache2.conf` | + | | Virtual hosts | `/etc/apache2/sites-available` | + | | | `/etc/apache2/sites-enabled` | + | **NGINX Web Server** | Main | `/etc/nginx/nginx.conf` | + | | Virtual hosts | `/etc/nginx/sites-available` | + | | | `/etc/nginx/sites-enabled` | + | **Cron** | Application | `/etc/cron.d` | + | | System-wide `cron` jobs | `/etc/crontab` | + | | User-specific `cron` jobs | `/var/spool/cron/crontabs` | + | **MySQL/MariaDB** | Main | `/etc/mysql` | + | **PostgreSQL** | Main | `/etc/postgresql` | + | **SSH** | Main | `/etc/ssh/sshd_config` | + | **Networking** | Hostname | `/etc/hostname` | + | | Hosts file | `/etc/hosts` | + | **Rsyslog** | Main | `/etc/rsyslog.conf` | + +- **Review Symbolic Links and Permissions**: Use CLI tools and commands to confirm that symbolic links and file permissions on your Linode match those on the source VM. Examples include: + + | Description | Command | + |---------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| + | List all symbolic links in folder (recursive). | `ls -Rla /path/to/folder \| grep "->"` | + | Calculate md5 hash for all files in a folder, then sort by filename and write to file. Then compare files from both VMs using `diff`. | `find /path/to/folder/ -type f -exec md5sum {} + \| sort -k 2 > hashes.txt` | + | Write to file the folder contents (recursive) with permissions, owner name, and group name. Then compare permissions files from both VMs using `diff`. | `tree /path/to/folder -fpuig > permissions.txt` | + +After deploying your Linode, confirm that the configuration (network settings, environment variables, and application dependencies) matches the source VM to avoid runtime issues. + +### Security and Access Controls + +AWS IAM roles govern instance access. To migrate these roles and permissions to Akamai Cloud: + +- Create Linode API tokens and fine-tune user permissions. +- Reproduce AWS security group policy rules in the Akamai Cloud Firewall or existing system firewall. +- Properly configure SSH keys and disable root login if not required. + +### Alternative Migration Options + +If exporting a disk image is not viable due to provider restrictions or image size constraints, consider these alternative migration options: + +- **Data-only Transfer**: Provision a Linode with resource levels comparable to your source VM, then use [rclone](https://rclone.org/) to move all data from your original VM to your new Linode. +- **Infrastructure-as-Code (IaC)**: Replicate your source VM on Linode using tools like [Ansible](https://docs.ansible.com/ansible/latest/index.html), [Terraform](https://www.terraform.io/), [Chef](https://www.chef.io/products/chef-infra), and [Puppet](https://www.puppet.com/why-puppet/use-cases/continuous-configuration-automation). These tools can help replicate server configurations, deploy applications, and ensure consistency. +- **Containerization**: Containerize workloads and deploy them to a [Linode Kubernetes Engine (LKE)](https://techdocs.akamai.com/cloud-computing/docs/linode-kubernetes-engine) cluster, eliminating the need to migrate the VM entirely. + +## Resources + +AWS: +- [EC2 export-image documentation](https://docs.aws.amazon.com/cli/latest/reference/ec2/export-image.html) + +Akamai Cloud: +- [Linode CLI and Object Storage](https://techdocs.akamai.com/cloud-computing/docs/using-the-linode-cli-with-object-storage) +- [Uploading an image](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) +- [Deploying an Image](https://techdocs.akamai.com/cloud-computing/docs/deploy-an-image-to-a-new-compute-instance) + +Other: +- [QEMU Disk Imaging Utility](https://www.qemu.org/download/) +- [rclone](https://rclone.org/) \ No newline at end of file diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/linode-create-instance-from-uploaded-image.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/linode-create-instance-from-uploaded-image.png new file mode 100644 index 00000000000..44fe64d8295 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-aws-ec2-to-akamai-using-disk-images/linode-create-instance-from-uploaded-image.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-create-image-form.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-create-image-form.png new file mode 100644 index 00000000000..f8b479d6cc4 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-create-image-form.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-create-snapshot.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-create-snapshot.png new file mode 100644 index 00000000000..6c7a8e7d8d5 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-create-snapshot.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-list-select.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-list-select.png new file mode 100644 index 00000000000..2f206d05dcf Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-disk-list-select.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-apply-resize.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-apply-resize.png new file mode 100644 index 00000000000..873dad4d144 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-apply-resize.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-overview.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-overview.png new file mode 100644 index 00000000000..ecae4cbf208 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-overview.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-confirm.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-confirm.png new file mode 100644 index 00000000000..c9b59bdf5f8 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-confirm.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-partition.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-partition.png new file mode 100644 index 00000000000..ffbc96aa03e Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-gparted-resize-partition.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-images-page.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-images-page.png new file mode 100644 index 00000000000..b749095320d Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-images-page.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-network-firewall-rules.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-network-firewall-rules.png new file mode 100644 index 00000000000..f1c5033113a Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-network-firewall-rules.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-project-id-modal.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-project-id-modal.png new file mode 100644 index 00000000000..bd5e5f24e01 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-project-id-modal.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-boot-disk-storage.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-boot-disk-storage.png new file mode 100644 index 00000000000..555d4939bde Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-boot-disk-storage.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instance-details.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instance-details.png new file mode 100644 index 00000000000..df64f7d304d Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instance-details.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instances-page.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instances-page.png new file mode 100644 index 00000000000..0a04e2ca8a2 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-instances-page.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-ip-addresses.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-ip-addresses.png new file mode 100644 index 00000000000..5e809b58dae Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-ip-addresses.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-machine-type-ui.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-machine-type-ui.png new file mode 100644 index 00000000000..30990e87dc2 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/gcp-vm-machine-type-ui.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/index.md b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/index.md new file mode 100644 index 00000000000..579f9407c79 --- /dev/null +++ b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/index.md @@ -0,0 +1,817 @@ +--- +slug: transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images +title: "Transfer VM From GCP Compute Engine to Akamai Using Disk Images" +description: "Two to three sentences describing your guide." +authors: ["Linode"] +contributors: ["Linode"] +published: 2025-05-28 +keywords: ['list','of','keywords','and key phrases'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +external_resources: +- '[Link Title 1](http://www.example.com)' +- '[Link Title 2](http://www.example.net)' +--- + +In modern cloud computing, virtual machine (VM) migration is a process that enables organizations to transition workloads between cloud platforms to optimize costs, improve performance, or enhance flexibility. By migrating VMs, organizations can select the capabilities of various cloud providers that best satisfy their business needs. + +This guide focuses on migrating a VM from Google Cloud Platform (GCP) to Akamai Cloud using disk images suggests how to plan, execute, and validate the migration. + +## Before You Begin + +1. Log in to your [Akamai Cloud](https://www.linode.com/cfe) account to prepare the destination environment. + +1. Create a [Linode API token (personal access token)](/docs/products/platform/accounts/guides/manage-api-tokens/) so you can authenticate with the Linode CLI. + +1. Install and configure the [Linode CLI](/docs/products/tools/cli/guides/install/) on your local system. + +1. You must also have access to a GCP account with sufficient permissions to work with Disks, Storage, and Build Jobs. + +1. Install and configure the [GCP CLI](https://cloud.google.com/sdk/docs/install-sdk) (`gcloud`) to interact with your GCP VM instances. + +1. Install [QEMU](https://www.qemu.org/) to convert the exported disk image into a format compatible with Akamai Cloud. + +{{< note >}} +This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you’re not familiar with the `sudo` command, see the [Users and Groups](/docs/guides/linux-users-and-groups/) guide. +{{< /note >}} + +## Preparing Your Compute Engine Image for Migration + +Before migrating, review your GCP environment to ensure compatibility with Akamai Cloud. Note any instance-specific dependencies, such as storage size, image type, or hardware requirements, that may impact the transition. + +Record the configuration details of your Compute Engine VM to help choose an [Akamai Cloud plan](https://www.linode.com/pricing/#compute-shared) that matches your resource needs after migration. + +{{< note >}} +[Images imported into Akamai Cloud](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) must be smaller than 6 GB unzipped or 5 GB zipped. Images exceeding the size limit are rejected during upload and not imported. +{{< /note >}} + +### Assess Current Compute Engine Requirements + +Assess your Compute Engine VM using either the GCP Console or the gcloud CLI. Use these methods to gather the CPU, memory, storage, networking, and firewall details needed for migration. + +{{< tabs >}} +{{< tab "GCP Console" >}} +#### Machine Type, CPU, and Memory + +1. In the GCP Console, navigate to **Compute Engine > VM instances**: + + ![GCP Console showing the VM instances page in Compute Engine.](gcp-vm-instances-page.png) + +1. Select the instance you intend to migrate to view its details: + + ![Details page for a selected Compute Engine VM instance.](gcp-vm-instance-details.png) + + Note the **Name** (e.g. `instance-20250208-003502`) and **Zone** (e.g. `us-west1-a`). + +1. In the **Machine Configuration** section of the **Details** page, review the **Machine type** (e.g. `e2-medium`): + + ![GCP VM details page showing the Machine configuration section with machine type.](gcp-vm-machine-type-ui.png) + + For this guide, the example Compute Instance VM has 2 CPUs and 4GB of memory. + +#### Storage + +4. Scroll to the **Storage > Boot disk** section to view the type and size of the storage disk associated with your VM: + + ![GCP VM storage section showing the boot disk type and size.](gcp-vm-boot-disk-storage.png) + +#### IP Addresses + +5. IP addresses are listed in the **Network Interfaces** section of the instance **Details** page: + + ![GCP VM details page showing internal and external IP addresses.](gcp-vm-ip-addresses.png) + +#### Security Groups and Firewall Rules + +6. In the **Network Interfaces** section, select the network name to view its associated firewall rules and other network settings: + + ![GCP network settings page showing firewall rules for the VM's network.](gcp-network-firewall-rules.png) +{{< /tab >}} +{{< tab "gcloud CLI" >}} +#### Machine Type + +1. List all projects in your account: + + ```command + gcloud projects list + ``` + + ```output + PROJECT_ID NAME PROJECT_NUMBER + gcp-vm-migration GCP VM Migration 123456789012 + another-project-id Another Project 987654321098 + ``` + +1. Set your desired {{< placeholder "PROJECT_ID" >}} to the active project in `gcloud` (e.g. `gcp-vm-migration`): + + ```command + gcloud config set project {{< placeholder "PROJECT_ID" >}} + ``` + + ```output + Updated property [core/project]. + ``` + +1. List all VM instances in the selected project: + + ```command + gcloud compute instances list + ``` + + ```output + NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS + instance-20250208-003502 us-west1-a e2-medium false 10.138.0.3 104.198.111.144 RUNNING + ``` + +1. Describe your instance to return its full machine type URL, replacing {{< placeholder "INSTANCE_NAME" >}} (e.g. `instance-20250208-003502`) and {{< placeholder "ZONE" >}} (e.g. `us-west1-a`): + + ```command + gcloud compute instances describe {{< placeholder "INSTANCE_NAME" >}} \ + --zone={{< placeholder "ZONE" >}} \ + --format="value(machineType)" + ``` + + The {{< placeholder "MACHINE_TYPE" >}} is the final part of the resulting URL (e.g. `e2-medium`): + + ```output + https://www.googleapis.com/compute/v1/projects/gcp-vm-migration-450215/zones/us-west1-a/machineTypes/e2-medium + ``` + +#### CPU and Memory + +5. Use the CLI to determine the CPU and memory configurations for this Compute Engine {{< placeholder "MACHINE_TYPE" >}} (e.g. `e2-medium`): + + ```command + gcloud compute machine-types describe {{< placeholder "MACHINE_TYPE" >}} \ + --zone={{< placeholder "ZONE" >}} \ + --format="table(name, guestCpus, memoryMb)" + ``` + + ```output + NAME GUEST_CPUS MEMORY_MB + e2-medium 2 4096 + ``` + + For this guide, the example Compute Instance VM has 2 CPUs and 4GB of memory. + +#### Storage + +6. View the disk(s) attached to your VM: + + ```command + gcloud compute disks list --zones={{< placeholder "ZONE" >}} + ``` + + ```output + NAME LOCATION SIZE_GB TYPE STATUS + instance-20250208-003502 us-west1-a 10 pd-balanced READY + ``` + +#### IP Addresses + +7. Run the following `gcloud` command to find the internal and external IP address of the running instance: + + ```command + gcloud compute instances list \ + --filter="name={{< placeholder "INSTANCE_NAME" >}}" \ + --format="table(name,networkInterfaces[0].accessConfigs[0].natIP,networkInterfaces[0].networkIP)" + ``` + + ```output + NAME NAT_IP NETWORK_IP + instance-20250208-003502 104.198.111.144 10.138.0.3 + ``` + +#### Security Groups and Firewall Rules + +8. Run the following `gcloud` command to find all the firewall rules for a VM: + + ```command + gcloud compute firewall-rules list --filter="network:default" + ``` + + ```output + NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED + default-allow-icmp default INGRESS 65534 icmp False + default-allow-internal default INGRESS 65534 tcp:0-65535,udp:0-65535,icmp False + default-allow-rdp default INGRESS 65534 tcp:3389 False + default-allow-ssh default INGRESS 65534 tcp:22 False + + To show all fields of the firewall, please show in JSON format: --format=json + To show all fields in table format, please see the examples in --help. + ``` +{{< /tab >}} +{{< /tabs >}} + +#### Optional: Back up Your Compute Engine Disk + +Before starting your migration, consider backing up the Compute Engine disk in case a restoration is needed in the future. + +{{< tabs >}} +{{< tab "GCP Console" >}} +1. In the **Storage** section of your Compute Instance **Details** page, select the disk associated with the VM you wish to export: + + ![GCP storage section showing list of disks for the VM.](gcp-disk-list-select.png) + +1. Select **Create Snapshot**: + + ![Snapshot creation interface for a selected GCP Compute Engine disk.](gcp-disk-create-snapshot.png) +{{< /tab >}} +{{< tab "gcloud CLI" >}} +Run the following `gcloud` command to create a backup of your GCP Compute Instance, replacing {{< placeholder "SNAPSHOT_NAME">}} with a name of your choosing (e.g. `my-vm-snapshot`): + +```command +gcloud compute snapshots \ + create {{< placeholder "SNAPSHOT_NAME" >}} \ + --source-disk={{< placeholder "DISK_NAME" >}} \ + --source-disk-zone={{< placeholder "ZONE" >}} +``` + +```output +Creating gce snapshot my-vm-snapshot...done. +``` +{{< /tab >}} +{{< /tabs >}} +## Migrating to Akamai Cloud + +Migrating a Google Compute Engine VM to Akamai Cloud involves the following steps: + +- Export the VM disk image from your Compute Engine instance. +- Resize and prepare the image file for import. +- Upload the compressed image to Akamai Cloud. +- Launch a new Linode Compute Instance from the uploaded image. +- Verify and configure the new instance. + +### Export Your Compute Engine VM Disk Image + +Export your VM to a Machine Image using either the Google Cloud Console or the `gcloud` CLI: +{{< tabs >}} +{{< tab "Google Cloud Console" >}} +1. In the Google Cloud Console, navigate to **Compute Engine > Images**: + + ![Google Cloud Console showing the Compute Engine Images page with the "Create Image" button highlighted.](gcp-images-page.png) + +1. Click **Create Image** at the top of the page. On the next screen, enter a name for the image, then your VM's disk as the **Source disk**: + + ![Google Cloud Console create image form with name and source disk fields highlighted.](gcp-create-image-form.png) + +1. Set any required location and encryption options, then click **Create**. +{{< /tab >}} +{{< tab "gcloud CLI" >}} +1. Before creating an image you must stop the VM if it is running: + + ```command + gcloud compute instances stop {{< placeholder "INSTANCE_NAME" >}} --zone={{< placeholder "ZONE" >}} + ``` + + ```output + Stopping instance(s) instance-20250208-003502...done. + ``` + +1. Run the following `gcloud` CLI command to create an image, replacing {{< placeholder "IMAGE_NAME" >}} with a name of your choosing (e.g. `my-vm-image`): + + ```command + gcloud compute images create {{< placeholder "IMAGE_NAME" >}} \ + --source-disk={{< placeholder "DISK_NAME" >}} \ + --source-disk-zone={{< placeholder "ZONE" >}} + ``` + + ```output + Created [https://www.googleapis.com/compute/v1/projects/gcp-vm-migration-450215/global/images/my-vm-image\]. + NAME PROJECT FAMILY DEPRECATED STATUS + my-vm-image gcp-vm-migration-450215 READY + ``` + +1. Confirm the image was created: + + ```command + gcloud compute images list --filter="name={{< placeholder "IMAGE_NAME" >}}" + ``` + + ```output + NAME PROJECT FAMILY DEPRECATED STATUS + my-vm-image gcp-vm-migration-450215 READY + ``` +{{< /tab >}} +{{< /tabs >}} + +The following steps (exporting and downloading the image) require the `gcloud` CLI, as these operations are not available through the Google Cloud Console: + +1. Create a Cloud Storage bucket to store the exported image. Replace {{< placeholder "BUCKET_NAME" >}} with a unique bucket name (e.g. `migration-vm-images`) and {{< placeholder "REGION" >}} with a supported region for Cloud Build image exports (e.g. `us` or `us-central1`). See [Google's list of supported regions](https://cloud.google.com/build/docs/locations#restricted_regions_for_some_projects): + + ```command + gcloud storage buckets create gs://{{< placeholder "BUCKET_NAME" >}} --location={{< placeholder "REGION" >}} + ``` + + ```output + Creating gs://migration-vm-images/... + ``` + +1. Export a compressed copy of the image to the bucket: + + ```command + gcloud compute images export \ + --destination-uri=gs://{{< placeholder "BUCKET_NAME" >}}/{{< placeholder "IMAGE_NAME" >}} \ + --image={{< placeholder "IMAGE_NAME" >}} + ``` + + ```output + Created [https://cloudbuild.googleapis.com/v1/projects/gcp-vm-migration-450215/builds/b6d6fbf5-bc51-4228-9ca5-c1b988477fe4\]. + Logs are available at [https://console.cloud.google.com/cloud-build/builds/b6d6fbf5-bc51-4228-9ca5-c1b988477fe4?project=133697932277\]. + [image-export]: 2025-02-08T15:39:47Z Fetching image "my-vm-image" from project "gcp-vm-migration-450215". + [image-export-ext]: 2025-02-08T15:39:48Z Validating workflow + [image-export-ext]: 2025-02-08T15:39:48Z Validating step "setup-disks" + [image-export-ext]: 2025-02-08T15:39:48Z Validating step "export-disk" + [image-export-ext.export-disk]: 2025-02-08T15:39:48Z Validating step "setup-disks" + [image-export-ext.export-disk]: 2025-02-08T15:39:48Z Validating step "run-export-disk" + ... + [image-export-ext]: 2025-02-08T15:39:50Z Uploading sources + [image-export-ext]: 2025-02-08T15:39:50Z Running workflow + [image-export-ext]: 2025-02-08T15:39:50Z Running step "setup-disks" (CreateDisks) + ... + [image-export-ext]: 2025-02-08T15:42:30Z Step "export-disk" (IncludeWorkflow) successfully finished. + [image-export-ext]: 2025-02-08T15:42:30Z Running step "delete-disks" (DeleteResources) + [image-export-ext.delete-disks]: 2025-02-08T15:42:30Z DeleteResources: Deleting disk "disk-image-export-ext". + [image-export-ext]: 2025-02-08T15:42:30Z Step "delete-disks" (DeleteResources) successfully finished. + [image-export-ext]: 2025-02-08T15:42:30Z Serial-output value -> source-size-gb:10 + [image-export-ext]: 2025-02-08T15:42:30Z Serial-output value -> target-size-gb:10 + [image-export-ext]: 2025-02-08T15:42:30Z Workflow "image-export-ext" cleaning up (this may take up to 2 minutes). + [image-export-ext]: 2025-02-08T15:42:30Z Workflow "image-export-ext" finished cleanup. + ``` + +```output +??? +``` + +1. Verify the file was exported, replacing {{< placeholder "BUCKET_NAME" >}} with your actual bucket name (e.g. `migration-vm-images`): + + ```command + gcloud storage ls gs://{{< placeholder "BUCKET_NAME" >}} + ``` + + ```output + gs://migration-vm-images/my-vm-image + ``` + +1. Download the file to your local machine: + + ```command + gsutil cp gs://{{< placeholder "BUCKET_NAME" >}}/{{< placeholder "IMAGE_NAME" >}} . + ``` + + ```output + Copying gs://migration-vm-images/my-vm-image... + | [1 files][ 10.0 GiB/ 10.0 GiB] 22.8 MiB/s + Operation completed over 1 objects/10.0 GiB. + ``` + +1. Confirm the download and check the current size of the compressed disk image file in megabytes: + + ```command + du -BM {{< placeholder "IMAGE_NAME" >}} + ``` + + ```output + 748M my-vm-image + ``` + +1. Decompress the downloaded archive: + + ```command + tar -xzvf {{< placeholder "IMAGE_NAME" >}} + ``` + + ```output + disk.raw + ``` + +1. Check the size of the uncompressed raw disk image: + + ```command + du -BM disk.raw + ``` + + ```output + 10241M disk.raw + ``` + + GCP persistent disks have a *minimum* size of 10 GB. An uncompressed size of 10 GB and a compressed size of just 750 MB indicates that the exported image includes a large amount of unused disk space. + +### Resize Disk Image + +To import a VM image into Akamai Cloud, it must be smaller than 5 GB zipped and 6 GB unzipped. If your *actual* disk usage is below those limits, you can reduce the image size by deallocating unused disk space and truncating the disk size. + +Shrinking the disk image involves using `parted` (or [`fdisk`](https://tldp.org/HOWTO/Partition/fdisk_partitioning.html)) and [`qemu-img`](https://qemu-project.gitlab.io/qemu/tools/qemu-img.html) on your local machine. These utilities operate on block devices, so you must attach the raw image using a [loopback device](https://wiki.osdev.org/Loopback_Device) before resizing partitions and truncating the file. + +1. Enable loopback support: + + ```command + sudo modprobe loop + ``` + +1. Attach the image to a free loop device: + + ```command + sudo losetup -f --show disk.raw + ``` + + ```output + /dev/loop3 + ``` + +1. Inspect partitions to find the main root partition number: + + ```command + sudo parted /dev/loop{{< placeholder "LOOP_NUMBER" >}} print + ``` + + In the example below, the main partition is number `1`: + + ```output + Model: Loopback device (loopback) + Disk /dev/loop3: 10.7GB + Sector size (logical/physical): 512B/512B + Partition Table: gpt + Disk Flags: + + Number Start End Size File system Name Flags + 14 1049kB 4194kB 3146kB bios_grub + 15 4194kB 134MB 130MB fat16 boot, esp + 1 134MB 10.7GB 10.6GB ext4 + ``` + +1. Reload partition info: + + ```command + sudo partprobe /dev/loop{{< placeholder "LOOP_NUMBER" >}} + ``` + +1. Mount the main partition: + + ```command + sudo mount /dev/loop{{< placeholder "LOOP_NUMBER" >}}p{{< placeholder "PARTITION_NUMBER" >}} /mnt + ``` + +1. Check used space: + + ```command + df -h /mnt + ``` + + In the example below, the main partition is actually only using 2.1 GB of disk space. + + ```output + Filesystem Size Used Avail Use% Mounted on + /dev/loop3p1 9.7G 2.1G 7.1G 23% /mnt + ``` + +1. Unmount the main partition: + + ```command + sudo umount /mnt + ``` + +1. Use `parted` to resize the partition to the actual usage plus a buffer of free space (e.g. `2.5GB`): + + ```command + sudo parted /dev/loop{{< placeholder "LOOP_NUMBER" >}} -- resizepart 1 2.5GB + ``` + + Enter `Yes` and press Enter when prompted: + + ```output + Warning: Shrinking a partition can cause data loss, are you sure you want to + continue? + Yes/No? Yes + + Information: You may need to update /etc/fstab. + ``` + +1. Check and resize the file system inside the resized partition: + + ```command + sudo e2fsck -f /dev/loop{{< placeholder "LOOP_NUMBER" >}}p{{< placeholder "PARTITION_NUMBER" >}} + sudo resize2fs /dev/loop{{< placeholder "LOOP_NUMBER" >}}p{{< placeholder "PARTITION_NUMBER" >}} + ``` + +1. Detach the loop device: + + ``` + sudo losetup -d /dev/loop{{< placeholder "LOOP_NUMBER" >}} + ``` + +1. Truncate the disk image file to match the new end: + + ```command + qemu-img resize --shrink {{< placeholder "IMAGE_NAME" >}} 2.5G + ``` + +1. Fix the GPT backup header to match the new size: + + ```command + sudo sgdisk --move-second-header {{< placeholder "IMAGE_NAME" >}} + ``` + +1. Verify the final file size: + + ```command + du -BM {{< placeholder "IMAGE_NAME" >}} + ``` + + ```output + 2500M my-vm-image + ``` + +#### OLD + +1. Use `sgdisk` to shrink the partition table to match the last used partition: + + ```command + sudo sgdisk --set-alternative-lba {{< placeholder "IMAGE_NAME" >}} + ``` + +1. Use [`qemu-img`](https://qemu-project.gitlab.io/qemu/tools/qemu-img.html) to shrink the disk image file, leaving some additional buffer space. For example, if your disk image is approximately 5.5 GB, shrink the image file to 5.8 GB: + + ```command + qemu-img resize -f raw --shrink {{< placeholder "IMAGE_NAME" >}} 5.8G + ``` + +1. Use [`gdisk`](https://linux.die.net/man/8/gdisk) to recreate the partition table headers using: + + ```command + sudo gdisk {{< placeholder "IMAGE_NAME" >}} + ``` + + Within `gdisk`, enter the following commands: + + - `x`: Switch to expert mode. + - `e`: Relocate backup GPT to end of disk. + - `w`: Write the new GPT to disk and exit. + - `Y`: Confirm write when prompted. + + ```output + ... + Command (? for help): x + + Expert command (? for help): e + Relocating backup data structures to the end of the disk + + Expert command (? for help): w + + Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!! + + Do you want to proceed? (Y/N): Y + OK; writing new GUID partition table (GPT) to my-vm-image. + Warning: The kernel is still using the old partition table. + The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) + The operation has completed successfully. + ``` + +1. Confirm that the resulting disk image file is now within the size constraints for import into Akamai Cloud: + + ```command + du -BM {{< placeholder "IMAGE_NAME" >}} + ``` + + ```output + 5940M my-vm-image + ``` + +1. Detach the loopback device: + + ```command + sudo losetup -d /dev/loop48 + ``` + +{{< note >}} +For a deeper dive into this image-shrinking technique, see [Shrinking images on Linux](https://softwarebakery.com/shrinking-images-on-linux). +{{< /note >}} + +### Import and Deploy VM Image on Akamai Cloud + +To provision a Linode by importing an existing VM image, ensure the image is in the proper format and compressed with `gzip`. + +#### Prepare Image File for Import + +Linode requires image files to use the `.img` extension. If your exported image file does not already have this extension, rename it accordingly. + +1. Rename the file to use the `.img` extension: + + ```command + mv my-vm-image my-vm-image.img + ``` + +1. Compress the image using `gzip` to reduce its size: + + ```command + gzip my-vm-image.img + ``` + +1. Confirm the compressed image was created and check its size: + + ```command + du -BM my-vm-image.img.gz + ``` + + ```output + 1060M my-vm-image.img.gz + ``` + +#### Upload the Compressed File to Akamai Cloud + +Use the Linode CLI to upload your compressed image file. Replace the filename with your specific `.gz` image, and specify the label, description, and region based on your use case. + +```command +linode-cli image-upload \ + --label "gcp-vm-migration" \ + --description "GCP VM Import" \ + --region "us-lax" \ + ./my-vm-image.img.gz +``` + +```output +┌-----------------------┬-----------┬----------------┐ +│ label │ is_public │ status │ +├-----------------------┼-----------┼----------------┤ +│ gcp-vm-migration │ False │ pending_upload │ +└-----------------------┴-----------┴----------------┘ +``` + +The upload process may take several minutes depending on the size of your image and network speed. + +#### Verify the Successful Image Upload + +After uploading the image, verify that is was processed and is available for use. Run the following command to list your private images: + +```command +linode-cli images list --is_public false +``` + +```output +┌------------------┬-----------------------┬-----------┬--------┐ +│ id │ label │ status │ size │ +├------------------┼-----------------------┼-----------┼--------┤ +│ private/30127625 │ gcp-vm-migration │ available │ 5940 │ +└------------------┴-----------------------┴-----------┴--------┘ +``` + +Check that the `status` is `available`. If the `status` is `pending`, wait a few minutes and try again. + +You can also monitor the upload status from the **Images** section of the Akamai Cloud Manager: + +![Akamai Cloud Manager showing a private image labeled gcp-vm-migration with status available.](linode-cloud-manager-private-image-status-gcp.png) + +#### Launch a Linode Compute Instance from the Uploaded Image + +Once your image is available, you can deploy it to a new Linode instance. For this command, provide the ID of your uploaded image (shown in the previous step). Also include the following values: + +- `--label`: A unique label for the instance. +- `--region`: The preferred deployment region. +- `--type`: The type of instance to deploy. +- `--root_pass`: A secure root password for SSH access. + +This example deploys a `g6-standard-2` Linode with 2 vCPUs, 80 GB storage, 4 GB RAM, and a 4000 Mbps transfer rate. This is a comparable configuration to the original GCP `e2-medium` VM instance, which also features 2 vCPUs and 4 GB RAM. See the [Akamai Cloud pricing page](https://www.linode.com/pricing/#compute-shared) for more details on available instance types and their associated costs. + +```command +linode-cli linodes create \ + --image {{< placeholder "IMAGE_ID" >}} \ + --label "migrated-from-gcp" \ + --region "us-lax" \ + --type "g6-standard-2" \ + --root_pass "{{< placeholder "ROOT_PASSWORD" >}}" +``` + +```output +┌-----------------------┬--------┬---------------┬--------------┐ +│ label │ region │ type │ status │ +├-----------------------┼--------┼---------------┼--------------┤ +│ migrated-from-gcp │ us-lax │ g6-standard-2 │ provisioning │ +└-----------------------┴--------┴---------------┴--------------┘ +``` + +By default, Linode boots instances using its own kernel. To instead boot from the kernel embedded in your imported image: + +1. Navigate to your Linode under **Compute > Linodes** in the Akamai Cloud Manager. + +1. Select your Linode instance. + +1. Open the **Configurations** tab at the bottom, then click **Edit**. + + ![Linode dashboard with the Configurations tab selected.](linode-configurations-tab.png) + +1. Under **Boot Settings**, select **Direct Disk** as the kernel option. + + ![Linode configuration editor showing Direct Disk selected under Boot Settings.](linode-select-direct-disk-kernel.png) + +1. Click **Save Changes**, then **Reboot** your Linode. + + ![Linode interface showing the Reboot button after saving configuration changes.](linode-reboot-after-config-save.png) + +After several minutes, your Linode instance should be running using the image exported from your GCP VM. + +### Configure and Validate the Linode Instance + +Migrating using a disk image exported from your GCP VM and disk ensures that the operating system and all installed software and services are preserved on the newly provisioned Linode. This reduces the time needed to reconfigure the Linode instance to closely match the original VM. + +However, you must still configure the Linode's networking to align with your workload. Refer to the configuration details from your original GCP Compute Engine VM and apply them to your Linode as appropriate: + +- [IP Addresses](https://techdocs.akamai.com/cloud-computing/docs/managing-ip-addresses-on-a-compute-instance) +- [Firewall Rules](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-cloud-firewalls) +- [Load Balancing](https://techdocs.akamai.com/cloud-computing/docs/nodebalancer) +- [DNS](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-dns-manager) + +Linode does not have a direct equivalent to GCP security groups. However, you can still implement a firewall with rules to control traffic. Options include: + +- [Akamai Cloud Firewall](https://techdocs.akamai.com/cloud-computing/docs/cloud-firewall) to set up inbound and outbound rules through the Akamai Cloud Manager, the Linode CLI, or API. +- [`iptables`](/docs/guides/control-network-traffic-with-iptables/) or [`ufw`](/docs/guides/configure-firewall-with-ufw/) to manage the Linux kernel firewall (Netfilter). + +To replicate GCP’s HTTPS LoadBalancers, use Akamai Cloud's [NodeBalancers](https://www.linode.com/products/nodebalancers/) to distribute traffic across multiple Linode instances. + +If you used Cloud DNS to route traffic to your GCP VM, you need to update your DNS records to route traffic to your new Linode instance instead. This may involve pointing your domain nameservers to Akamai Cloud and creating DNS rules within the Akamai Cloud Manager. + +After completing your configurations, test your Linode instance to verify that the migration was successful. Validation steps may include: + +- **Check Running Services**: Confirm that all critical services (e.g. web servers, databases, and application processes) are running as expected and configured to start on boot. +- **Test Application Functionality**: Access your applications through their web interface or API endpoints to confirm that they behave as expected, including core functionality and error handling. +- **Inspect Resource Utilization**: Monitor the Linode's CPU, memory, and disk usage to ensure the system performs within acceptable thresholds post-migration. +- **Validate DNS Configuration**: Ensure that any DNS changes are propagating correctly, pointing to your Linode instance, and resolving to the expected IP addresses. +- **Check External Connectivity**: Verify that the Linode can access any required external resources (e.g. third-party APIs, databases, or storage) and that outbound requests succeed. +- **Review Logs**: Examine system and application logs for errors or warnings that might indicate migration-related issues. +- **Backup and Snapshot Functionality**: To safeguard your data post-migration, confirm that backups and snapshots can be created successfully. +- **Verify Externally Attached Storage**: Ensure that any additional storage volumes, block devices, or network-attached storage are properly mounted and accessible. Check `/etc/fstab` entries and update disk mappings as needed. + +## Additional Considerations + +### Cost Management + +Review the pricing for your current GCP Compute Engine VM instance including [compute](https://cloud.google.com/compute/vm-instance-pricing?hl=en), [storage](https://cloud.google.com/compute/disks-image-pricing?hl=en#tg1-t0), and [bandwidth](https://cloud.google.com/vpc/network-pricing?hl=en). Compare those costs with the [Akamai Cloud pricing plans](https://www.linode.com/pricing/) using [Akamai’s Cloud Computing Calculator](https://www.linode.com/cloud-computing-calculator/) to estimate your usage. + +### Data Consistency and Accuracy + +After importing your image and launching your Linode, verify that all expected files, configurations, and application data are intact. Verification steps may include: + +- **Generate and Compare File Checksums**: Use tools like `md5sum` to generate checksums of both the source VM and your Linode. Ensure the checksums match to confirm data integrity. +- **Count Files and Directories**: Use commands like `find` or `ls` to count the number of files and directories in key locations (e.g. `find /path -type f | wc -l`). Compare these counts between the source VM and your Linode to identify any discrepancies. +- **Check Application Logs and Settings**: Compare configuration files, environment variables, and application logs between the source VM and your Linode to confirm they are identical (or appropriately modified for the new environment). Common locations to review may include: + + | Application | Configuration | Location | + |-----------------------|---------------------------|--------------------------------| + | **Apache Web Server** | Main | `/etc/apache2/apache2.conf` | + | | Virtual hosts | `/etc/apache2/sites-available` | + | | | `/etc/apache2/sites-enabled` | + | **NGINX Web Server** | Main | `/etc/nginx/nginx.conf` | + | | Virtual hosts | `/etc/nginx/sites-available` | + | | | `/etc/nginx/sites-enabled` | + | **Cron** | Application | `/etc/cron.d` | + | | System-wide `cron` jobs | `/etc/crontab` | + | | User-specific `cron` jobs | `/var/spool/cron/crontabs` | + | **MySQL/MariaDB** | Main | `/etc/mysql` | + | **PostgreSQL** | Main | `/etc/postgresql` | + | **SSH** | Main | `/etc/ssh/sshd_config` | + | **Networking** | Hostname | `/etc/hostname` | + | | Hosts file | `/etc/hosts` | + | **Rsyslog** | Main | `/etc/rsyslog.conf` | + +- **Review Symbolic Links and Permissions**: Use CLI tools and commands to confirm that symbolic links and file permissions on your Linode match those on the source VM. Examples include: + + | Description | Command | + |---------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| + | List all symbolic links in folder (recursive). | `ls -Rla /path/to/folder | grep "\->"` | + | Calculate md5 hash for all files in a folder, then sort by filename and write to file. Then, compare files from both VMs using `diff`. | `find /path/to/folder/ -type f -exec md5sum {} + | sort -k 2 > hashes.txt` | + | Write to file the folder contents (recursive) with permissions, owner name, and group name. Then, compare permissions files from both VMs using `diff`. | `tree /path/to/folder -fpuig > permissions.txt` | + +After deploying your Linode, confirm that configurations (network settings, environment variables, and application dependencies) match the source VM to avoid runtime issues. + +### Security and Access Controls + +GCP IAM roles govern instance access. To migrate these roles and permissions to Akamai Cloud: + +- Create Linode API tokens and fine-tune user permissions. +- Reproduce GCP security group policy rules on the Akamai Cloud Firewall or existing system firewall. +- Properly configure SSH keys and disable root login if not required. + +### Alternative Migration Options + +If exporting a disk image is not viable due to provider restrictions or image size limits, consider these alternative migration options: + +- **Data-only Transfer**: Provision a Linode with resource levels comparable to your source VM, then use [rclone](https://rclone.org/) to move all data from your source VM to your new Linode. +- **Infrastructure-as-Code (Ia)**: Replicate your source VM on Akamai Cloud using tools like [Ansible](https://docs.ansible.com/ansible/latest/index.html), [Terraform](https://www.terraform.io/), [Chef](https://www.chef.io/products/chef-infra), and [Puppet](https://www.puppet.com/why-puppet/use-cases/continuous-configuration-automation). These tools can help replicate server configurations, deploy applications, and ensure consistency. +- **Containerization**: Containerize workloads and deploy them to a [Linode Kubernetes Engine (LKE)](https://techdocs.akamai.com/cloud-computing/docs/linode-kubernetes-engine) cluster, eliminating the need to migrate the VM entirely. + +## Resources + +GCP: +- [GCP CLI Documentation](https://cloud.google.com/sdk/docs) +- [GCP Export Custom Image](https://cloud.google.com/compute/docs/images/export-image) +- [VM Migration Guide](https://cloud.google.com/migrate/virtual-machines/docs/5.0/reference/rest/v1) +- [Regions with Build Capabilities](https://cloud.google.com/build/docs/locations#restricted_regions_for_some_projects) +- [Troubleshooting VM Export and Import](https://cloud.google.com/compute/docs/troubleshooting/troubleshooting-import-export-images) + +Akamai Cloud: +- [Linode CLI and Object Storage](https://techdocs.akamai.com/cloud-computing/docs/using-the-linode-cli-with-object-storage) +- [Uploading an image](https://techdocs.akamai.com/cloud-computing/docs/upload-an-image) +- [Deploying an Image](https://techdocs.akamai.com/cloud-computing/docs/deploy-an-image-to-a-new-compute-instance) + +Other: +- [QEMU Disk Imaging Utility](https://www.qemu.org/download/) +- [rclone](https://rclone.org/) +- [Shrinking images on Linux](https://softwarebakery.com//shrinking-images-on-linux) \ No newline at end of file diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-gcp.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-gcp.png new file mode 100644 index 00000000000..f26a21e2b5f Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-cloud-manager-private-image-status-gcp.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-configurations-tab.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-configurations-tab.png new file mode 100644 index 00000000000..78779880901 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-configurations-tab.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-reboot-after-config-save.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-reboot-after-config-save.png new file mode 100644 index 00000000000..d67b8511843 Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-reboot-after-config-save.png differ diff --git a/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png new file mode 100644 index 00000000000..817d572efff Binary files /dev/null and b/docs/guides/platform/migrate-to-linode/transfer-vm-from-gcp-compute-engine-to-akamai-using-disk-images/linode-select-direct-disk-kernel.png differ