Migrate ECS instances across regions by using Alibaba Cloud CLI
Migrate an Elastic Compute Service (ECS) instance across regions by using Alibaba Cloud CLI. Create a custom image of the source instance, copy it to the destination region, and launch a new instance from the copied image.
How it works
Cross-region migration uses a custom image to replicate your ECS instance disks in a new region.
-
Create a custom image from the source instance. This captures the operating system, applications, and data on all disks.
-
Copy the custom image to the destination region.
-
Create a new instance in the destination region from the copied image.
-
Verify the new instance to ensure all applications and services function as expected.
-
Release the source resources to avoid incurring unnecessary costs.
Before you begin
Limitations
-
Instances with local disks are not supported because snapshots cannot be created for them.
-
This method does not support creating images that contain snapshots of system disks and data disks from instances with local SSDs. For more information, see Instance families with local SSDs (i series).
-
The source instance can be in a classic network or a VPC. The destination instance must be in a VPC.
-
The instance type must be available in the destination zone.
Billing
-
Snapshots created as part of the custom image incur charges. For more information, see Snapshot billing.
Planning considerations
-
Create a VPC, vSwitch, and security group in the destination region.
-
The new instance has different metadata (instance ID, private IP address, MAC address). Update applications or scripts that depend on this metadata, such as MAC-bound licenses or cluster IP configurations. For more information, see Instance metadata.
Prerequisites
-
Install and configure the Alibaba Cloud CLI. For more information, see the Installation guide and Configure credentials.
-
Ensure you have permissions for the required ECS API operations (
CreateImage,CopyImage,RunInstances, andDeleteInstance).
Step 1: Create a custom image from the source instance
Call the CreateImage operation to create a custom image of your source instance. For more information, see Create a custom image from an instance.
If the source instance is running, this operation stops it for several minutes to ensure snapshot data consistency.
aliyun ecs CreateImage \
--RegionId 'cn-hangzhou' \
--ImageName 'source-image-for-migration' \
--InstanceId 'i-bp1g6zv0ce8oghu7****'
The response returns the new image ID.
{
"ImageId": "m-bp146shijn7hujku****",
"RequestId": "C8B26B44-0189-443E-9816-*******"
}
Save the ImageId for the next step.
Step 2: Copy the image to the destination region
Wait for the image status to become Available before copying. Check the status by calling the DescribeImages operation.
Call the CopyImage operation to copy the image to the destination region. This example copies an image from China (Hangzhou) to China (Beijing).
aliyun ecs CopyImage \
--RegionId 'cn-hangzhou' \
--ImageId 'm-bp146shijn7hujku****' \
--DestinationRegionId 'cn-beijing' \
--DestinationImageName 'migrated-image-beijing'
The response returns a new ImageId for the copied image in the destination region.
{
"ImageId": "m-bp1h46wfpjsjastd****",
"RequestId": "473469C7-AA6F-4DC5-B3DB-A3DC0DE3C83E"
}
Save this new ImageId for the next step.
Step 3: Create the destination instance
Call the RunInstances operation to create a new instance from the copied image in the destination region. For more information, see Create an instance with Custom Launch.
aliyun ecs RunInstances \
--RegionId 'cn-beijing' \
--ImageId 'm-bp1h46wfpjsjastd****' \
--InstanceType 'ecs.g6.large' \
--SecurityGroupId 'sg-2zea9dbddva****' \
--VSwitchId 'vsw-2zep7vc25mjc1****' \
--InstanceName 'migrated-instance-beijing' \
--PasswordInherit true \
--InternetChargeType 'PayByTraffic' \
--SystemDisk.Size '40' \
--SystemDisk.Category 'cloud_essd' \
--InstanceChargeType 'PostPaid' \
--InternetMaxBandwidthOut '10'
PasswordInherit is set to true, so the new instance uses the same password as the source instance.
The response returns the new instance ID.
{
"RequestId": "473469C7-AA6F-4DC5-B3DB-A3DC0DE3****",
"InstanceIdSets": {
"InstanceIdSet": [
"i-bp67acfmxazb4pd2****"
]
}
}
Step 4: Verify the destination instance
After the new instance starts, connect to it and verify:
-
The file system and data on the system and data disks match the source instance.
-
Applications and services start and function correctly.
-
Resource associations that depend on instance metadata (IP addresses, MAC addresses) are updated.
Step 5: Release the source resources
After verifying the new instance works correctly, release the original resources to avoid unnecessary charges.
Releasing instances and deleting images and snapshots are irreversible. Verify your data migration before proceeding.
-
Release the source instance: Call the DeleteInstance operation. For more information, see Release an instance.
aliyun ecs DeleteInstance --InstanceId 'i-bp1g6zv0ce8oghu7****' --Force true -
Delete the custom images: Call the DeleteImage operation for both the source and copied images. For more information, see Delete a custom image.
# Delete the source region image aliyun ecs DeleteImage --RegionId 'cn-hangzhou' --ImageId 'm-bp146shijn7hujku****' # Delete the destination region image aliyun ecs DeleteImage --RegionId 'cn-beijing' --ImageId 'm-bp1h46wfpjsjastd****' -
Delete the related snapshots: Call the DeleteSnapshot operation for each snapshot created by the imaging process.
aliyun ecs DeleteSnapshot --SnapshotId 's-bp1c0doj0taqyzzl****'
Automate the migration with scripts
The following scripts provide a basic framework you can adapt for your migration.
Script examples:
Bash
To run this script, you must have the jq tool installed.
#!/usr/bin/env bash
# Source instance ID
SRC_INSTANCE_ID="i-bp1g6zv0ce8oghu7****"
# Source instance region ID
SRC_REGION_ID="cn-hangzhou"
# Destination region ID
DST_REGION_ID="cn-beijing"
# Destination instance zone ID
DST_ZONE_ID="cn-beijing-h"
# Source instance type
SRC_INSTANCE_TYPE="ecs.e-c1m1.large"
# Source instance system disk category
SRC_SYSTEM_DISK_CATEGORY="cloud_auto"
# Source instance system disk size
SRC_SYSTEM_DISK_SIZE=40
# Output log
function log {
local level="$1"
local message="$2"
echo "$(date +'%Y-%m-%d %H:%M:%S') [$level] $message"
}
# Wrap Alibaba Cloud CLI
function invoke_aliyun_command() {
local service="$1"
local action="$2"
shift 2
local -a params=("$@")
response=$(aliyun "$service" "$action" "${params[@]}")
exit_code=$?
if [ $exit_code -eq 0 ]; then return 0; fi
log "ERROR" "Failed to invoke aliyun command: aliyun $service $action ${params[*]}"
exit 1
}
# Wait for resource to be available
function wait_resource_available() {
local service="$1"
local action="$2"
local region_id="$3"
local resource_type="$4"
local resource_id="$5"
local -a params=(
"--region" "$region_id"
"--RegionId" "$region_id"
"--${resource_type}Id" "$resource_id"
)
if [ "$resource_type" == "Image" ]; then
params+=("--Status" "Creating,Waiting,Available")
fi
local current_status
local current_progress
local timeout=1200
local interval=20
local end_time=$(( $(date +%s) + timeout ))
while (( $(date +%s) < end_time )); do
invoke_aliyun_command "$service" "$action" "${params[@]}"
current_status=$(echo "$response" | jq -r '.. | .Status? // empty' | head -n1)
current_progress=$(echo "$response" | jq -r '.. | .Progress? // empty' | head -n1)
log "INFO" "${resource_type} status: $current_status"
if [[ -n "$current_progress" ]]; then
log "INFO" "Creation progress: $current_progress"
fi
if [[ "$current_status" == "Available" ]]; then return 0; fi
sleep "$interval"
done
}
# Create image
log "INFO" "Creating source image from instance '$SRC_INSTANCE_ID'"
src_img_params=(
"--region" "$SRC_REGION_ID"
"--RegionId" "$SRC_REGION_ID"
"--InstanceId" "$SRC_INSTANCE_ID"
"--ImageName" "cli-src-img"
)
invoke_aliyun_command ecs CreateImage "${src_img_params[@]}"
src_img_id=$(echo "$response" | jq -r .ImageId)
wait_resource_available ecs DescribeImages "$SRC_REGION_ID" "Image" "$src_img_id"
log "INFO" "Source image created: '$src_img_id'"
# Copy image to destination region
log "INFO" "Copying image to region: '$DST_REGION_ID'"
dst_img_params=(
"--region" "$SRC_REGION_ID"
"--RegionId" "$SRC_REGION_ID"
"--DestinationRegionId" "$DST_REGION_ID"
"--ImageId" "$src_img_id"
"--DestinationImageName" "cli-dst-img"
)
invoke_aliyun_command ecs CopyImage "${dst_img_params[@]}"
dst_img_id=$(echo "$response" | jq -r .ImageId)
wait_resource_available ecs DescribeImages "$DST_REGION_ID" "Image" "$dst_img_id"
log "INFO" "Destination image copied: '$dst_img_id'"
# Create VPC
log "INFO" "Creating VPC"
dst_vpc_params=(
"--region" "$DST_REGION_ID"
"--RegionId" "$DST_REGION_ID"
"--CidrBlock" "10.0.0.0/8"
"--VpcName" "cli-dst-vpc"
)
invoke_aliyun_command ecs CreateVpc "${dst_vpc_params[@]}"
dst_vpc_id=$(echo "$response" | jq -r .VpcId)
wait_resource_available "Vpc" "DescribeVpcAttribute" "$DST_REGION_ID" "Vpc" "$dst_vpc_id"
log "INFO" "VPC created: '$dst_vpc_id'"
# Create a vSwitch
log "INFO" "Creating VSwitch"
dst_vsw_params=(
"--region" "$DST_REGION_ID"
"--RegionId" "$DST_REGION_ID"
"--ZoneId" "$DST_ZONE_ID"
"--VpcId" "$dst_vpc_id"
"--CidrBlock" "10.1.1.0/24"
)
invoke_aliyun_command vpc CreateVSwitch "${dst_vsw_params[@]}"
dst_vsw_id=$(echo "$response" | jq -r .VSwitchId)
wait_resource_available "vpc" "DescribeVSwitchAttributes" "$DST_REGION_ID" "VSwitch" "$dst_vsw_id"
log "INFO" "VSwitch created: '$dst_vsw_id'"
# Create security group
log "INFO" "Creating security group"
dst_sg_params=(
"--region" "$DST_REGION_ID"
"--RegionId" "$DST_REGION_ID"
"--SecurityGroupName" "cli-dst-sg"
"--VpcId" "$dst_vpc_id"
"--SecurityGroupType" "normal"
)
invoke_aliyun_command ecs CreateSecurityGroup "${dst_sg_params[@]}"
dst_sg_id=$(echo "$response" | jq -r .SecurityGroupId)
log "INFO" "Security group created: '$dst_sg_id'"
# Create a pay-as-you-go ECS instance in the destination region
log "INFO" "Creating ECS instance in zone: '$DST_ZONE_ID'"
dst_instance_params=(
"--region" "$DST_REGION_ID"
"--RegionId" "$DST_REGION_ID"
"--ImageId" "$dst_img_id"
"--SecurityGroupId" "$dst_sg_id"
"--VSwitchId" "$dst_vsw_id"
"--InstanceType" "$SRC_INSTANCE_TYPE"
"--InstanceName" "cli-dst-ecs"
"--PasswordInherit" "true"
"--SystemDisk.Category" "$SRC_SYSTEM_DISK_CATEGORY"
"--SystemDisk.Size" "$SRC_SYSTEM_DISK_SIZE"
"--InstanceChargeType" "PostPaid"
)
invoke_aliyun_command ecs RunInstances "${dst_instance_params[@]}"
dst_instance_id=$(echo "$response" | jq -r '.InstanceIdSets.InstanceIdSet[0]')
log "INFO" "ECS instance created: '$dst_instance_id'"
Powershell
# Set error exit policy
$ErrorActionPreference = "Stop"
# Set character encoding
chcp 65001 | Out-Null
[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# Source instance ID
$SRC_INSTANCE_ID = "i-bp1g6zv0ce8oghu7****"
# Source instance region ID
$SRC_REGION_ID = "cn-hangzhou"
# Destination region ID
$DST_REGION_ID = "cn-beijing"
# Destination instance zone ID
$DST_ZONE_ID = "cn-beijing-h"
# Source instance type
$SRC_INSTANCE_TYPE = "ecs.e-c1m1.large"
# Source instance system disk category
$SRC_SYSTEM_DISK_CATEGORY = "cloud_auto"
# Source instance system disk size
$SRC_SYSTEM_DISK_SIZE = 40
# Output log
function Log {
param ([string]$Level, [string]$Message)
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] $Message"
}
# Wrap Alibaba Cloud CLI
function Invoke-AliyunCommand {
param ([string]$Service, [string]$Action, [array]$Params)
$response = aliyun $Service $Action $Params
if ($LASTEXITCODE -eq 0) { return $response | ConvertFrom-Json }
Log "ERROR" "Failed to call aliyun command: aliyun $Service $Action $Params"
exit 1
}
# Get nested property value
function Get-NestedPropertyValue {
param (
[object]$Object,
[string]$PropertyPath
)
$parts = $PropertyPath -split '\.'
$value = $Object
foreach ($part in $parts) {
$value = $value.$part
}
return $value
}
# Wait for resource to be available
function Wait-ResourceAvailable {
param (
[string]$Service,
[string]$Action,
[object]$Params,
[string]$StatusPath,
[string]$ProgressPath
)
$timeout = 1200
$interval = 20
$endTime = (Get-Date).AddSeconds($timeout)
while ((Get-Date) -lt $endTime) {
$response = Invoke-AliyunCommand $Service $Action $Params
$currentStatus = Get-NestedPropertyValue $response $StatusPath
Log "INFO" "Resource status: $currentStatus"
if ($ProgressPath) {
$currentProgress = Get-NestedPropertyValue $response $ProgressPath
Log "INFO" "Creation progress: $currentProgress"
}
if ("Available" -eq $currentStatus) { return }
Start-Sleep -Seconds $interval
}
}
# Create image
Log "INFO" "Creating source image from instance '$SRC_INSTANCE_ID'"
$srcImgId = (Invoke-AliyunCommand -Service "ecs" -Action "CreateImage" -Params @(
"--region", $SRC_REGION_ID,
"--RegionId", $SRC_REGION_ID,
"--InstanceId", $SRC_INSTANCE_ID,
"--ImageName", "cli-src-img"
)).ImageId
Wait-ResourceAvailable -Service "ecs" -Action "DescribeImages" -Params @(
"--region", $SRC_REGION_ID,
"--RegionId", $SRC_REGION_ID,
"--ImageId", $srcImgId,
"--Status", "Creating,Waiting,Available"
) -StatusPath "Images.Image.Status" -ProgressPath "Images.Image.Progress"
Log "INFO" "Source image created: '$srcImgId'"
# Copy image to destination region
Log "INFO" "Copying image to region: '$DST_REGION_ID'"
$dstImgId = (Invoke-AliyunCommand -Service "ecs" -Action "CopyImage" -Params @(
"--region", $SRC_REGION_ID,
"--RegionId", $SRC_REGION_ID,
"--DestinationRegionId", $DST_REGION_ID,
"--ImageId", $srcImgId,
"--DestinationImageName", "cli-dst-img"
)).ImageId
Wait-ResourceAvailable -Service "ecs" -Action "DescribeImages" -Params @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--ImageId", $dstImgId,
"--Status", "Creating,Waiting,Available"
) -StatusPath "Images.Image.Status" -ProgressPath "Images.Image.Progress"
Log "INFO" "Destination image copied: '$dstImgId'"
# Create VPC
Log "INFO" "Creating VPC"
$dstVpcId = (Invoke-AliyunCommand -Service "vpc" -Action "CreateVpc" -Params @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--CidrBlock", "10.0.0.0/8",
"--VpcName", "cli-dst-vpc"
)).VpcId
Wait-ResourceAvailable -Service "Vpc" -Action "DescribeVpcAttribute" -Params @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--VpcId", $dstVpcId
) -StatusPath "Status"
Log "INFO" "VPC created: '$dstVpcId'"
# Create a vSwitch
Log "INFO" "Creating VSwitch"
$dstVSwitchId = (Invoke-AliyunCommand vpc CreateVSwitch @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--ZoneId", $DST_ZONE_ID,
"--VpcId", $dstVpcId,
"--CidrBlock", "10.1.1.0/24"
)).VSwitchId
Wait-ResourceAvailable -Service "Vpc" -Action "DescribeVSwitchAttributes" -Parameters @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--VSwitch", $dstVSwitchId
) -StatusPath "Status"
Log "INFO" "VSwitch created: '$dstVSwitchId'"
# Create security group
Log "INFO" "Creating security group"
$dstSecurityGroupId = (Invoke-AliyunCommand ecs CreateSecurityGroup @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--SecurityGroupName", "cli-dst-sg",
"--VpcId", $dstVpcId,
"--SecurityGroupType", "normal"
)).SecurityGroupId
Log "INFO" "Security group created: '$dstSecurityGroupId'"
# Create a pay-as-you-go ECS instance in the destination region
Log "INFO" "Creating ECS instance in zone: '$DST_ZONE_ID'"
$dstInstanceId = (Invoke-AliyunCommand ecs RunInstances @(
"--region", $DST_REGION_ID,
"--RegionId", $DST_REGION_ID,
"--ImageId", $dstImgId,
"--SecurityGroupId", $dstSecurityGroupId,
"--VSwitchId", $dstVSwitchId,
"--InstanceType", $SRC_INSTANCE_TYPE,
"--InstanceName", "cli-dst-ecs",
"--PasswordInherit", "true",
"--SystemDisk.Category", $SRC_SYSTEM_DISK_CATEGORY,
"--SystemDisk.Size", $SRC_SYSTEM_DISK_SIZE,
"--InstanceChargeType", "PostPaid"
)).InstanceIdSets.InstanceIdSet[0]
Log "INFO" "ECS instance created: '$dstInstanceId'"
Log "INFO" "Script execution completed successfully."
References
Replicate instance across regions with custom image (console-based method)