Reader Question: Can I Stop Instances on a Schedule?

Trevor Emailed Me to Ask About Improving the EBS Snapshot Code to Stop Test Instances

Posted by Ryan S. Brown on Mon, Jan 18, 2016
In Reader Question
Tags: lambda, ec2, schedules

Last week, Trevor (@trevorpaxton) emailed me with a question about building on my series of articles on EBS snapshotting and snapshot pruning to manage dev/test instances and keep costs down.

I’ve been building a lot of our rebuilding a lot Dev environments in AWS to cut costs, automate, etc and your blog post about scheduling EBS snapshots using lamba has really inspired me. I’ve implemented it and I’m automatically taking daily snapshots and keeping them for a week. Works great!

I’d like to manage all backup, retention and uptime policies with tags so I’ve attempted to use your methods and Boto3 to start and stop instances that have the tag “9pmstop” at 9pm every day. I published what I have so far on Github.

Since the stop-instances call takes a list of instance IDs, you can use a list comprehension to pull out all the IDs of instances that match your tag (9pmstop).

You’d replace these lines 26 through 40 where I was iterating over block devices for each instance with this:

instance_ids = [ins['InstanceId'] for ins in instances]
response = ec.stop_instances(InstanceIds=instance_ids)
print "Stopping %d instances NOW" % len(response['StoppingInstances']

What that’ll do is pull the instance ID strings from all the instances we queried out of the reservation list, then send them to be stopped.

The final code should look like this:

import boto3
ec = boto3.client('ec2')

def lambda_handler(event, context):
    reservations = ec.describe_instances(
        Filters=[
            {'Name': 'tag-key', 'Values': ['9pmstop']},
        ]
    ).get(
        'Reservations', []
    )

    # Flatten the list of all instances from all reservations into one list
    instances = sum(
        [
            [i for i in r['Instances']]
            for r in reservations
        ], [])

    print "Found %d instances to be shut down at 9pm" % len(instances)

    # get all the instance IDs from the list of instances
    instance_ids = [ins['InstanceId'] for ins in instances]

    response = ec.stop_instances(InstanceIds=instance_ids)
    print "Stopping %d instances NOW" % len(response['StoppingInstances']

Since you’re scheduling this, it sounds like you run these instances for the same amount of time every day. The new scheduled reserved instances feature could save you some money. Expect about a 5-15% discount on scheduled reservations compared to on-demand instances.

If you have a question or suggestion about anything Lambda-related, send an email to ryan@serverlesscode.com or tweet @ryan_sb and I’ll help you out.


Tweet this, send to Hackernews, or post on Reddit