Recover an application from server snapshot
In the unlikely event of an emergency it may be required at some point that you perform an application recovery from snapshot. Nex!™ storage racks are designed to be snapshotted every six hours with a two weeks retention when the underlying platform allows it (e.g. AWS EBS snapshots). The steps described in this article are only applicable for applications using persistent storage (e.g. database addons). Web applications - e.g. ones using the maestrano/web-ruby image - are stateless and therefore not subject to backups.
1 - Choosing the backup to use
Login to the Nex!™ console and adapt the steps below based on your recovery needs
# Retrieve the container that you wish to recover container = App.find_by(name: "someapp").cube_instances.first # OR container = Addon.find_by(name: "someaddon").cube_instances.first # List the recent backups for the storage rack associated with this container # /!\ Keep in mind that the "created_at" timestamp is displayed in UTC time /!\ puts container.storage_rack.rack_backups.where("created_at > ?",2.days.ago).map { |b| "#{b.id} | #{b.created_at}" } # From the list displayed above, select the storage backup you want backup = container.storage_rack.rack_backups.find(123456)
2 - Provision a storage server from this backup
The next step is to make this backup available for retrieval. In order to do that, we are going to create a StorageRack using the AWS AMI attached to the backup.
# Build a new StorageRack from the backup image and flag it as "non usable" by setting the # available storage units (su) to a large negative value backup_storage = StorageRack.new(vpc_region: backup.vpc_region, machine_image: backup.backup_id) backup_storage.available_su = -1000 # Save the storage rack and provision it backup_storage.save! backup_storage.provision! # After a couple of minutes, your backup StorageRack should be ready backup_storage.reload.status #=> "running" backup_storage.ssh("echo 1") #=> {:stdout=>"1\n", :stderr=>"", :exit_code=>0, :exit_signal=>nil} # The backup StorageRack is now available to us to perform the recovery
3 - Perform the recovery
Now that the backup StorageRack is available, we're going to stop the application, change its storage rack to the backup one then start the application. This will have the effect to start the application from backup and perform the recovery.
Finally we will reassign the previous storage rack to the application and terminate the backup StorageRack.
# Capture the current application StorageRack active_storage = container.storage_rack # Stop the application container.stop! # Wait until the application is stopped container.reload.status #=> "stopped" # Change the application StorageRack to point to the backup StorageRack container.storage_rack = backup_storage container.save! # Start the application container.start! # Wait until the application is up container.reload.status #=> "running" # The application is now rolled back. Let's proceed to re-assigning the previous StorageRack # To do so we perform a CubeStorageTransfer from the backup StorageRack to the active StorageRack # This transfer will: # 1) re-assign the cube to the StorageRack it should point to # 2) copy the **backup storage** cube data to the active StorageRack transfer = CubeStorageTransfer.create!(cube_instance: container, src_storage_rack: container.storage_rack, dst_storage_rack: active_storage) transfer.provision! # Wait for the transfer to be done transfer.reload.status #=> "provisioned" # Reload the cube and ensure it's pointing to the right storage rack container.reload.storage_rack == active_storage #=> true # Finally delete the backup storage rack backup_storage.terminate! unless backup_storage.reload.cube_instances.any? # Wait until the backup_storage is terminated backup_storage.reload.status #=> "terminated"