file

Use the system disk snapshot of the preemptive instance to create a custom image, and then create an instance based on the custom image to restore the data on the recycled instance

Preemptive instances may be forcibly recycled due to price factors or changes in market supply and demand. If your preemptive instance has important data saved, to avoid data loss, you can create a snapshot of the instance's system disk and use the snapshot to create a custom image, and then use the image to create a new preemptive instance to complete data recovery within the instance.

working principle

When you use preemptive instances, the instances may be forcibly recycled due to price factors or changes in market supply and demand. Before being fully recycled, the instances will enter a locked state and trigger the interruption event of preemptive instances.

You can set the monitoring mechanism based on this event, and set the system disk not to be released with the instance during the normal operation of the instance. After receiving the interruption event of the preemptive instance, the system automatically creates a snapshot for the system disk through the Java SDK 2.0 code, and then automatically creates a custom image based on the snapshot of the system disk. You can use the created custom image to create a new preemptive instance, Realize data recovery within the instance.

explain

After setting that the system disk is not released with the instance, even if the preemptive instance is released, the system disk snapshot creation, custom image creation and other work will not be affected.

In the example scenario provided in this article, the operation and maintenance workflow is as follows:

 image

prerequisite

  • Alibaba Cloud account and corresponding Access Key have been prepared.

    When using the Alibaba Cloud SDK for Java, you need to set the AccessKey information of the AliCloud account. For the access method of AccessKey, see Create AccessKey

  • The environment variables ALIABAA_CLOUD_ACCESS_KEY_ID and ALIABAA_CLOUD_ACCESS_KEY_SECRET have been configured. See Configure environment variables

  • Java SDK 2.0 has been installed in the development environment.

    You need to add the following dependencies in the Maven project. See Install Java SDK

     <dependencies> <dependency> <groupId>com.aliyun</groupId> <artifactId>ecs20140526</artifactId> <version>5.1.8</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.5</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> </dependencies>

matters needing attention

important

The sample code provided in this article is for reference only, and does not guarantee that your instance will complete image creation and data recovery within 5 minutes.

The preemptive instance will send an instance interrupt message at least 5 minutes in advance, but the specific time taken for data recovery depends on factors such as the image type of your instance and the file size of the system disk. For example, the larger the system disk file, the longer the recovery time. You must evaluate and verify the sample code yourself before using it.

Restrictions on use

During the data recovery process when the preemptive instance is recycled, the following restrictions exist:

  • To ensure that disk snapshots are not lost, it is recommended to turn off the function that snapshots are released with disks.

  • If the preemptive instance contains a data disk and there is important data in the data disk, it is recommended that the data disk be set not to be released with the instance.

  • When you call ModifyDiskAttribute The attribute "Do not release with instance" (DeleteWithInstance=false) is set in the interface. Once the ECS instance attached to the disk is securely locked and marked with "OperationLocks" "LockReason" : "security" When the instance is released, the DeleteWithInstance attribute of the disk will be ignored and the instance will be released at the same time.

    explain

    You can set DiskIds.N Parameters batch modify attributes such as the name, description, and whether to release with the instance of multiple block storage.

Step 1: Create a preemptive instance

This step provides CreateSpotInstance The code mainly uses ECS RunInstances Interface to create preemptive instances.

 import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.models.RunInstancesRequest; import com.aliyun.ecs20140526.models.RunInstancesResponse; public class CreateSpotInstance { static Client client; //Specify the region ID. The ECS instance you create after specifying belongs to this region. static String regionId = "cn-hangzhou"; //Specify the zone ID. The ECS instance you create after specifying belongs to this zone. static String zoneId = "cn-hangzhou-i"; //Specifies the instance type used by the created ECS instance. static String instanceType = "ecs.e-c1m1.large"; //Specifies the image ID used by the created ECS instance. static String imagesId = "aliyun_3_9_x64_20G_alibase_20231219.vhd"; //Specify the switch ID of the created ECS instance. static String vSwitchId = "<your-vSwitchId>"; //Specify the security group ID of the created ECS instance. static String securityGroupId = "<your-securityGroupId>"; //Specify the preemption policy. static String spotStrategy = "SpotAsPriceGo"; //Modify the length of time you need to keep the preemptive instance. When the retention duration cannot be determined, please set it to 0. static Integer spotDuration = 0; //Specify the login password of the ECS instance. static String password = "<your-password>"; public static void main(String[] args) throws Exception { client = createClient(); createInstance(); } private static Client createClient() throws Exception { //The disclosure of project code may lead to the disclosure of AccessKey and threaten the security of all resources under the account. The following code examples are for reference only. //It is recommended to use a more secure STS mode. For more authentication access methods, see: https://help.aliyun.com/document_detail/378657.html  com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_ID is set in the code running environment. .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_SECRET is set in the code running environment. .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); //Endpoint Please refer to https://api.aliyun.com/product/Ecs config.endpoint = "ecs-cn-hangzhou.aliyuncs.com"; return new Client(config); } //Create an instance. public static String createInstance() { try { //Set the RunInstances parameter and send the request. RunInstancesRequest request = new RunInstancesRequest(); request.setRegionId(regionId); request.setZoneId(zoneId); request.setInstanceType(instanceType); request.setSpotDuration(spotDuration); request.setSpotStrategy(spotStrategy); request.setImageId(imagesId); request.setVSwitchId(vSwitchId); request.setSecurityGroupId(securityGroupId); //The preemption policy will take effect only when the value of InstanceChargeType is PostPaid. request.setInstanceChargeType("PostPaid"); request.setPassword(password); request.setInternetMaxBandwidthOut(1); //Receive the return result of the call and output the created ECS instance ID. RunInstancesResponse response = client.runInstances(request); if (null == response.getBody().getInstanceIdSets() || response.getBody().getInstanceIdSets().getInstanceIdSet().isEmpty()) { return null; } String instanceId = response.getBody().getInstanceIdSets().getInstanceIdSet().get(0); System. out. println ("created instance ID:"+instanceId); return instanceId; } catch (Exception e) { e.printStackTrace(); } return null; } }

Step 2: Set the system disk not to be released with the instance

This step provides DiskRelated The code mainly uses ECS ModifyDiskAttribute The interface setting system disk is not released with the instance.

 import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.models.DescribeDisksRequest; import com.aliyun.ecs20140526.models.DescribeDisksResponse; import com.aliyun.ecs20140526.models.DescribeDisksResponseBody.DescribeDisksResponseBodyDisksDisk; import com.aliyun.ecs20140526.models.ModifyDiskAttributeRequest; import com.aliyun.ecs20140526.models.ModifyDiskAttributeResponse; import org.apache.commons.collections4.CollectionUtils; public class DiskRelated { static Client client; /** *Please change the regionId to the region ID of your preemptive instance. */ static String regionId = "cn-hangzhou"; /** *The instance ID of the preemptive instance. */ //static String instanceId = "<your-instance-id>"; static String instanceId = "i-bp18zj904wqnw5mc****"; public static void main(String[] args) throws Exception { client = createClient(); DescribeDisksResponseBodyDisksDisk disk = getDisks(); if(null == disk){ System.out.println("disk not exist"); return; } String diskId = disk.getDiskId(); modifyDiskAttribute(diskId); Boolean b = diskNotDeleteWithInstance(); if(b){ //If setting the system disk not to be released with the instance for the first time fails, reset it. modifyDiskAttribute(diskId); } } /** *Query the system disk details. */ public static DescribeDisksResponseBodyDisksDisk getDisks(){ DescribeDisksRequest request = new DescribeDisksRequest(); request.setRegionId(regionId); request.setInstanceId(instanceId); request.setDiskType("system"); try { DescribeDisksResponse response = client.describeDisks(request); if(CollectionUtils.isEmpty(response.getBody().getDisks().getDisk())){ System.out.println(("disk not exist. instanceId: " + instanceId)); return null; } DescribeDisksResponseBodyDisksDisk disk = response.getBody().getDisks() .getDisk().get(0); return disk; } catch (Exception e) { e.printStackTrace(); } return null; } /** *Set the system disk not to be released with the instance. */ public static void modifyDiskAttribute(String diskId){ ModifyDiskAttributeRequest request = new ModifyDiskAttributeRequest(); request.setDeleteWithInstance(false); request.setRegionId(regionId); request.setDiskId(diskId); try { ModifyDiskAttributeResponse response = client.modifyDiskAttribute(request); System.out.println(response.getBody().getRequestId()); } catch (Exception e) { e.printStackTrace(); } } /** *Query whether the system disk is released with the instance. */ public static Boolean diskNotDeleteWithInstance(){ DescribeDisksResponseBodyDisksDisk disks = getDisks(); if (disks.getDeleteWithInstance()){ System.out.println(("disk is delete with instance")); }else { System.out.println(("disk not delete with instance")); } return disks.getDeleteWithInstance(); } private static Client createClient() throws Exception { //The disclosure of project code may lead to the disclosure of AccessKey and threaten the security of all resources under the account. The following code examples are for reference only. com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_ID is set in the code running environment. .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_SECRET is set in the code running environment. .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); //Endpoint Please refer to https://api.aliyun.com/product/Ecs config.endpoint = "ecs-cn-hangzhou.aliyuncs.com"; return new Client(config); } }

Step 3: Automatically create a custom image after monitoring the interrupt event

When a preemptive instance is monitored for an interrupt event, the system automatically creates a snapshot of the system disk through Java code, and then automatically creates a custom image based on the snapshot of the system disk.

This step provides CreateSpotImage The code calls the following interfaces in turn to implement functions:

  • call DescribeInstances Monitor the status of preemptive instances.

  • When the preemptive instance is monitored to generate an interrupt event, call CreateSnapshot Create a system disk snapshot and call DescribeSnapshots Query the snapshot status.

  • After creating a system disk snapshot, call CreateImage , create a custom image based on the created system disk snapshot.

  • After creating a custom image, call DescribeImages Monitors the status of a custom image. When the image becomes available, a prompt is returned.

 import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.models.CreateImageRequest; import com.aliyun.ecs20140526.models.CreateImageResponse; import com.aliyun.ecs20140526.models.CreateSnapshotRequest; import com.aliyun.ecs20140526.models.CreateSnapshotResponse; import com.aliyun.ecs20140526.models.DescribeDisksRequest; import com.aliyun.ecs20140526.models.DescribeDisksResponse; import com.aliyun.ecs20140526.models.DescribeDisksResponseBody.DescribeDisksResponseBodyDisksDisk; import com.aliyun.ecs20140526.models.DescribeImagesRequest; import com.aliyun.ecs20140526.models.DescribeImagesResponse; import com.aliyun.ecs20140526.models.DescribeImagesResponseBody.DescribeImagesResponseBodyImagesImage; import com.aliyun.ecs20140526.models.DescribeInstancesRequest; import com.aliyun.ecs20140526.models.DescribeInstancesResponse; import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances; import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance; import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstanceOperationLocksLockReason; import com.aliyun.ecs20140526.models.DescribeSnapshotsRequest; import com.aliyun.ecs20140526.models.DescribeSnapshotsResponse; import com.aliyun.ecs20140526.models.DescribeSnapshotsResponseBody.DescribeSnapshotsResponseBodySnapshotsSnapshot; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; import java.util.List; import com.alibaba.fastjson.JSON; public class CreateSpotImage { static Client client; //Please change the regionId to the region ID of your preemptive instance. static String regionId = "cn-hangzhou"; //The instance ID of the preemptive instance. static String instanceId = "<your-instanceId>"; public static void main(String[] args) throws Exception { client = createClient(); //Step 1: Wait for the preemptive instance to be recycled, and generate an interrupt event. waitForInstanceMarked(); String diskId = getDiskId(); //Step 2: When the preemptive instance generates an interrupt event, the system disk snapshot is automatically created. String snapshotId = createSnapshot(diskId); //Step 3: Wait until the system disk snapshot is created successfully. waitCreateSnapshotSuccess(snapshotId); //Step 4: Create a custom image based on the system disk snapshot. String imageId = createImage(snapshotId); //Step 5: Wait until the custom image is created successfully. waitCreateImageSuccess(imageId); } private static Client createClient() throws Exception { //The disclosure of project code may lead to the disclosure of AccessKey and threaten the security of all resources under the account. The following code examples are for reference only. com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_ID is set in the code running environment. .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_SECRET is set in the code running environment. .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); //Endpoint Please refer to https://api.aliyun.com/product/Ecs config.endpoint = "ecs-cn-hangzhou.aliyuncs.com"; return new Client(config); } //Monitor the status of preemptive instances, and output instance related information when an interrupt event occurs. public static void waitForInstanceMarked() { //Convert the object to a JSON string. List<String> instanceIds = Lists.newArrayList(); instanceIds.add(instanceId); String instanceIdStr = JSON.toJSONString(instanceIds); boolean isMarked = false; //Judge whether preemptive instances generate interrupt events. while (! isMarked) { try { //Set the DescribeInstances parameter to send the request. DescribeInstancesRequest request = new DescribeInstancesRequest(); //Specify the region where the preemptive instance is located. request.setRegionId(regionId); //Specify preemptive instance ID query. request.setInstanceIds(instanceIdStr); //Receive the return result of the call. DescribeInstancesResponse response = client.describeInstances(request); //Get the return results related to preemptive instances. DescribeInstancesResponseBodyInstances instances = response.getBody().getInstances(); //If the instance information is not queried, it will jump out of the loop. if (CollectionUtils.isEmpty(instances.getInstance())) { break; } DescribeInstancesResponseBodyInstancesInstance instance = instances.getInstance().get(0); //If the queried instance is not interrupted, restart the cycle. if (instance.getOperationLocks() == null || instance.getOperationLocks().getLockReason().size() == 0) { continue; } for (DescribeInstancesResponseBodyInstancesInstanceOperationLocksLockReason lockReason : instance .getOperationLocks().getLockReason()) { //If the queried instance is interrupted, the specified instance ID and the reason for the interruption will be output. System.out.println("instance:" + instance.getInstanceId() + "-->lockReason:" + lockReason.getLockReason() + ",vmStatus:" + instance.getStatus()); if ("Recycling".equals(lockReason.getLockReason())) { isMarked = true; } } Thread.sleep(2 * 1000); } catch (Exception e) { e.printStackTrace(); } } } public static String getDiskId(){ String diskId = null; DescribeDisksRequest request = new DescribeDisksRequest(); request.setRegionId(regionId); request.setInstanceId(instanceId); request.setDiskType("system"); try { DescribeDisksResponse response = client.describeDisks(request); List<DescribeDisksResponseBodyDisksDisk> disks = response.getBody().getDisks().getDisk(); if (CollectionUtils.isEmpty(disks) ){ System.out.println("disk not exist. instance: " + instanceId); return null; } diskId = disks.get(0).getDiskId(); } catch (Exception e) { e.printStackTrace(); } return diskId; } /** *Create a system disk snapshot. */ public static String createSnapshot(String diskId){ CreateSnapshotRequest request = new CreateSnapshotRequest(); request.setDiskId(diskId); request.setSnapshotName("disk_test"); try { CreateSnapshotResponse  response= client.createSnapshot(request); System.out.println(JSON.toJSONString(response.getBody())); System.out.println(response.getBody().getSnapshotId()); return response.getBody().getSnapshotId(); } catch (Exception e) { e.printStackTrace(); } return null; } /** *Query whether the system disk snapshot was created successfully. */ public static void waitCreateSnapshotSuccess(String snapshotId){ boolean isSuccess = false; while (! isSuccess) { DescribeSnapshotsResponseBodySnapshotsSnapshot snapshot = describeSnapshots(snapshotId); if (null == snapshot) { System.err.println("image not exist. imageId: " + snapshotId); break; } if("accomplished".equals(snapshot.getStatus())){ System.out.println("snapshot created successfully."); isSuccess = true; } } } /** *Call DescribeSnapshots to query the system disk snapshot status. */ public static DescribeSnapshotsResponseBodySnapshotsSnapshot describeSnapshots(String snapshotId){ DescribeSnapshotsRequest request = new DescribeSnapshotsRequest(); request.setRegionId(regionId); List<String> snapshotIds = Lists.newArrayList(snapshotId); String s = JSON.toJSONString(snapshotIds); request.setSnapshotIds(s); try { DescribeSnapshotsResponse response = client.describeSnapshots(request); if (CollectionUtils.isEmpty(response.getBody().getSnapshots().getSnapshot())) { return null; } return  response.getBody().getSnapshots().getSnapshot().get(0); } catch (Exception e) { e.printStackTrace(); } return null; } //Create a custom image. public static String createImage(String snapshotId) { try { //Set the CreateImage parameter to send the request. CreateImageRequest request = new CreateImageRequest(); request.setRegionId(regionId); request.setSnapshotId(snapshotId); request.setImageName("image_test"); //Receive the return result of the call, and output the created custom image ID. CreateImageResponse response = client.createImage(request); System.out.println("imageID:" + response.getBody().getImageId()); return response.getBody().getImageId(); } catch (Exception e) { e.printStackTrace(); } return null; } //Query whether the image creation is successful. public static void waitCreateImageSuccess(String imageId) { boolean isSuccess = false; while (! isSuccess) { DescribeImagesResponseBodyImagesImage image = describeImage(imageId); if (null == image) { System.err.println("image not exist. imageId: " + imageId); break; } if ("Available".equals(image.getStatus())) { System.out.println("Image created successfully."); isSuccess = true; } } } //Call DescribeImages to monitor the image status. public static DescribeImagesResponseBodyImagesImage describeImage(String imageId) { try { Thread.sleep(6 * 60 * 1000); DescribeImagesRequest imagesRequest = new DescribeImagesRequest(); imagesRequest.setRegionId(regionId); imagesRequest.setImageId(imageId); imagesRequest.setPageSize(100); DescribeImagesResponse imagesResponse = client.describeImages(imagesRequest); if (null == imagesResponse.getBody().getImages() || CollectionUtils.isEmpty(imagesResponse.getBody().getImages().getImage())) { return null; } return imagesResponse.getBody().getImages().getImage().get(0); } catch (Exception e) { e.printStackTrace(); } return null; } }

Step 4: Use a custom image to create a new preemptive instance to restore data

This step provides CreateSpotInstanceFromImage The code calls ECS's RunInstances Interface to specify the created custom image to create a new preemptive instance.

 import com.aliyun.ecs20140526.Client; import com.aliyun.ecs20140526.models.RunInstancesRequest; import com.aliyun.ecs20140526.models.RunInstancesResponse; public class CreateSpotInstanceFromImage { static Client client; //Specifies the region ID of the instance. It is recommended to be consistent with the region of the source preemptive instance. static String regionId = "cn-hangzhou"; //Specifies the zone ID of the instance. It is recommended to be consistent with the zone of the source preemptive instance. static String zoneId = "cn-hangzhou-i"; //Specifies the instance type used by the created ECS instance. static String instanceType = "ecs.s6-c1m1.small"; //Specifies the created custom image ID. static String imagesId = "<your-imagesId>"; //Specify the switch ID of the created ECS instance. static String vSwitchId = "<your-vSwitchId>"; //Specify the security group ID of the created ECS instance. static String securityGroupId = "<your-securityGroupId>"; //Specify the preemption policy. static String spotStrategy = "SpotAsPriceGo"; //Modify the length of time you need to keep the preemptive instance. When the retention duration cannot be determined, please set it to 0. static Integer spotDuration = 0; //Specify the login password of the ECS instance. static String password = "<your-password>"; public static void main(String[] args) throws Exception { client = createClient(); createInstance(); } private static Client createClient() throws Exception { //The disclosure of project code may lead to the disclosure of AccessKey and threaten the security of all resources under the account. The following code examples are for reference only. com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_ID is set in the code running environment. .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) //Required. Please ensure that the environment variable ALIABAA_CLOUD_ACCESS_KEY_SECRET is set in the code running environment. .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); //Endpoint Please refer to https://api.aliyun.com/product/Ecs config.endpoint = "ecs-cn-hangzhou.aliyuncs.com"; return new Client(config); } //Call RunInstances to create an instance. public static String createInstance() { try { RunInstancesRequest request = new RunInstancesRequest(); request.setRegionId(regionId); request.setZoneId(zoneId); request.setInstanceType(instanceType); request.setSpotDuration(spotDuration); request.setSpotStrategy(spotStrategy); request.setImageId(imagesId); request.setVSwitchId(vSwitchId); request.setSecurityGroupId(securityGroupId); request.setInstanceChargeType("PostPaid"); request.setPassword(password); request.setInternetMaxBandwidthOut(1); RunInstancesResponse response = client.runInstances(request); if (null == response.getBody().getInstanceIdSets() || response.getBody().getInstanceIdSets().getInstanceIdSet().isEmpty()) { return null; } String instanceId = response.getBody().getInstanceIdSets().getInstanceIdSet().get(0); System. out. println ("created instance ID:"+instanceId);; return instanceId; } catch (Exception e) { e.printStackTrace(); } return null; } }

Related Documents

If you store important data in the data disk on the preemptive instance, you can recover the data on the data disk in the following ways:

  • Introduction to this page (1)