This repository contains a demo project created as part of my DevOps studies in the TechWorld with Nana – DevOps Bootcamp.
Demo Project: Data Backup & Restore
Technologies used: Python, Boto3, AWS
Project Description:
- Write a Python script that automates creating backups for EC2 Volumes
- Write a Python script that cleans up old EC2 Volume snapshots
- Write a Python script that restores EC2 Volumes
- Python 3.12+ and uv for dependency management
- An AWS account with permissions to manage EC2 instances, EBS volumes and snapshots
- Boto3 — the AWS SDK for Python (EC2 client reference)
- schedule — for running the backups on a recurring basis
Install Python dependencies:
uv syncConfigure AWS credentials at ~/.aws/credentials:
[default]
aws_access_key_id = AKIA...
aws_secret_access_key = ...And the default region at ~/.aws/config:
[default]
region = eu-central-1All scripts in this project target
eu-central-1. If you use a different region, update theregion_nameargument (and theAvailabilityZonein the restore script) accordingly.
Launch 2 instances:
- Number of instances:
2 - Instance type:
t2.micro - Storage:
1 volume — 8 GiB
Tag the instances — name one dev and the other prod:
Confirm each instance has its volume attached:
Boto3 docs:
import boto3
ec2_client = boto3.client('ec2', region_name='eu-central-1')
volumes = ec2_client.describe_volumes()
for volume in volumes['Volumes']:
new_snapshot = ec2_client.create_snapshot(
VolumeId=volume['VolumeId']
)
print(new_snapshot)Run
python3 volume-backups.pyCheck snapshots in AWS Dashboard
import boto3
import schedule
import time
ec2_client = boto3.client('ec2', region_name='eu-central-1')
def create_volume_snapshots():
volumes = ec2_client.describe_volumes()
for volume in volumes['Volumes']:
new_snapshot = ec2_client.create_snapshot(
VolumeId=volume['VolumeId']
)
print(new_snapshot)
schedule.every().day.do(create_volume_snapshots)
while True:
schedule.run_pending()
time.sleep(1)For a quick demo — shorten the interval to a few seconds:
schedule.every(20).seconds.do(create_volume_snapshots)First, tag the production volume. Navigate to the prod instance → Storage → select its attached volume:
Set the volume name to prod:
Then filter describe_volumes by that tag so only the prod volume is backed up (Filters reference):
volumes = ec2_client.describe_volumes(
Filters=[
{
'Name': 'tag:Name',
'Values': ['prod']
}
]
)python3 volume-backups.pyCheck the source volume id — it should match the prod volume:
Doc: describe_snapshots
First, list the snapshots you own, sorted newest-first (reverse=True):
import boto3
from operator import itemgetter
ec2_client = boto3.client('ec2', region_name='eu-central-1')
snapshots = ec2_client.describe_snapshots(
OwnerIds=['self']
)
sorted_by_date = sorted(snapshots['Snapshots'], key=itemgetter('StartTime'), reverse=True)
for snap in snapshots['Snapshots']:
print(snap['StartTime'])
print('############')
for snap in sorted_by_date:
print(snap['StartTime'])With the list sorted newest-first, slicing [2:] skips the two most recent and deletes everything older:
Boto3 doc: delete_snapshot
import boto3
from operator import itemgetter
ec2_client = boto3.client('ec2', region_name='eu-central-1')
snapshots = ec2_client.describe_snapshots(
OwnerIds=['self']
)
sorted_by_date = sorted(snapshots['Snapshots'], key=itemgetter('StartTime'), reverse=True)
for snap in sorted_by_date[2:]:
response = ec2_client.delete_snapshot(
SnapshotId=snap['SnapshotId']
)
print(response)Run:
python3 cleanup-snapshots.pyCheck the AWS dashboard — only the 2 most recent snapshots remain:
import boto3
from operator import itemgetter
ec2_client = boto3.client('ec2', region_name='eu-central-1')
volumes = ec2_client.describe_volumes(
Filters=[
{
'Name': 'tag:Name',
'Values': ['prod']
}
]
)
for volume in volumes['Volumes']:
snapshots = ec2_client.describe_snapshots(
OwnerIds=['self'],
Filters=[
{
'Name': 'volume-id',
'Values': [volume['VolumeId']]
}
]
)
sorted_by_date = sorted(snapshots['Snapshots'], key=itemgetter('StartTime'), reverse=True)
for snap in sorted_by_date[2:]:
response = ec2_client.delete_snapshot(
SnapshotId=snap['SnapshotId']
)
print(response)Grab the prod instance id from the AWS dashboard:
Boto3 docs:
boto3.resourcedescribe_volumes— filtered byattachment.instance-iddescribe_snapshotscreate_volume- Volume resource — used to poll
vol.state - Instance resource and its
attach_volumeaction
Get the device id:
A new volume can't reuse a device name already in use, so change the device from /dev/xvda to /dev/xvdb.
Replace
instance_idwith your ownprodinstance id, and make sureAvailabilityZonematches the instance's AZ — a volume can only attach to an instance in the same Availability Zone. The script pollsvol.stateuntil the new volume isavailable, then attaches it.
import boto3
import time
from operator import itemgetter
ec2_client = boto3.client('ec2', region_name='eu-central-1')
ec2_resource = boto3.resource('ec2', region_name='eu-central-1')
instance_id = 'i-0b62c30dfaaf087c5'
device_id = '/dev/xvdb'
volumes = ec2_client.describe_volumes(
Filters=[
{
'Name': 'attachment.instance-id',
'Values': [instance_id]
}
]
)
instance_volume = volumes['Volumes'][0]
print(instance_volume)
snapshots = ec2_client.describe_snapshots(
OwnerIds=['self'],
Filters=[
{
'Name': 'volume-id',
'Values': [instance_volume['VolumeId']]
}
]
)
latest_snapshot = sorted(snapshots['Snapshots'], key=itemgetter('StartTime'), reverse=True)[0]
print(latest_snapshot['StartTime'])
new_volume = ec2_client.create_volume(
SnapshotId=latest_snapshot['SnapshotId'],
AvailabilityZone='eu-central-1a',
TagSpecifications=[
{
'ResourceType': 'volume',
'Tags': [
{
'Key': 'Name',
'Value': 'prod'
}
]
}
]
)
while True:
vol = ec2_resource.Volume(new_volume['VolumeId'])
print(vol.state)
if vol.state == 'available':
ec2_resource.Instance(instance_id).attach_volume(
VolumeId=new_volume['VolumeId'],
Device=device_id
)
break
time.sleep(1)Run:
python3 restore-volume.pyCheck the restored volume on AWS — it's attached to the prod instance as a second device:
Tear down everything created from the AWS console once you're done:
- Instances
- Snapshots
- Volumes

















