Scheduling automatic snapshots for AWS EC2

Snapshots

Snapshots are your backups in AWS. You’d need backups if anything goes wrong with your server and restoring the backup is your only solution. Hopefully, you would never need to do that, but backups are called backups for a reason. You can always create snapshots of your ec2 instance volumes from the management console by selecting a volume and clicking Actions -> Create Snapshot. You can also schedule an automatic snapshot creation through the AWS Cloudwatch which is detailed here. However, I wanted a simpler solution. So I decided to create scripts of my own and use the built-in schedulers of the OS.

Requirements

You must have AWS CLI installed. Refer to this page for installation instructions. If you are using Windows server, you also need to have powershell. Once you have the AWS CLI installed, execute aws configure to configure your credentials and region.

Windows Script

@echo off
setlocal enabledelayedexpansion
set snapshotname=mysnapshot
set /a retention=7
powershell -Command "Get-Date((Get-Date).AddDays(-%retention%)) -format yyyy-MM-dd" > targetdate.txt
set /p targetdate= snapshot.txt
for /F %%i in (snapshot.txt) do (
    aws ec2 delete-snapshot --snapshot-id %%i
)
powershell -Command "(New-Object System.Net.WebClient).DownloadString('http://169.254.169.254/latest/meta-data/instance-id')" > instid.txt
set /p instanceid= volumes.txt
for /F %%i in (volumes.txt) do (
  aws ec2 create-snapshot --volume-id %%i --description "%Date% %Time%" --query "{ID:SnapshotId}" --output text > snapshot.txt
  set /p snapshotid=

Linux Script

#!/bin/bash
snapshotname=mysnapshot
retention=7
targetdate=$(date +%F -d "-$retention days")
deleteid=$(aws ec2 describe-snapshots --filters Name=start-time,Values="$targetdate*" Name=tag-key,Values="Name" Name=tag-value,Values="blogs" --query 'Snapshots[*].{ID:SnapshotId}' --output text)
if [ $deleteid ]
    then
        aws ec2 delete-snapshot --snapshot-id $deleteid
fi
instanceid=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
for volumeid in $(aws ec2 describe-volumes --filters Name=attachment.instance-id,Values=$instanceid --query "Volumes[*].{ID:VolumeId}" --output text)
do
    rightnow=$(date)
    snapshotid=$(aws ec2 create-snapshot --volume-id $volumeid --description "$rightnow" --query "{ID:SnapshotId}" --output text)
    aws ec2 create-tags --resources $snapshotid --tags Key=Name,Value=$snapshotname
done

What the script does

The script tries to find and delete snapshots with the same name tag created on the date calculated by (today’s date – retention date). Then the script grabs the server machine’s instance id from the metadata. The script uses that instance id to get the volume ids of all the volumes attached to that instance. Looping through each volume id, the script initiates snapshot creation and timestamps the description field (you can modify it to be more descriptive). Since the newly created snapshot has an empty name tag, the last line of the script adds a name tag. Change set snapshotname=mysnapshot to name it however you want. Also, change retention=7 to the number of days you want to keep past snapshots. Note that the script will delete snapshots that are exactly 7 days old. Anything older than that will not be touched. The Windows version creates three text files to save outputs of aws commands. If you wish to delete them, add del instid.txt snapshot.txt volumes.txt at the end of the script.

How to use

For Windows version, copy everything in the Windows Script section and save it into a batch file, i.e. create-snapshot.bat. Change the snapshotname to your liking. Execute the script first to verify that it’s working correctly (check the Snapshots section in the AWS management console to verify the new snapshot). Create a new task from Task Scheduler (Windows Administrative Tools -> Task Scheduler or Administrative Tools -> Task Scheduler). Create a schedule under the Triggers tab and set the batch file to execute under the Actions tab. Important: I had trouble running the scheduled task until I used a local account (not administrator). Be sure to select Run whether user is logged on or not option under the general tab.

For Linux, copy everything in the Linux Script section and save it into a bash script, i.e. create-snapshot.sh. Change the snapshotname line and execute the script to verify that it’s working. Schedule in cron by executing crontab -e. You would use the line below in crontab to have the script execute daily at 3 a.m.

0 3 * * * bash /home/ec2-user/create-snapshot.sh

Important: If you do not want the cron job to execute in UTC time (and display snapshot description in UTC time), which is the default, set the server’s timezone to your local timezone. You’d need to reboot your server after changing the timezone.

Notes

  • These scripts do not delete old snapshots. Updated scripts will now delete old snapshots.
  • Snapshots are NOT AMIs. They cannot be launched.
  • To restore a snapshot, you must:
    1. create a new volume from the snapshot.
    2. detach the old volume from the instance (stopping instance if needed).
    3. attach the new volume under the same device id.

1 thought on “Scheduling automatic snapshots for AWS EC2

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.