This tutorial aims at guiding your first steps at controlling your EC2 instances from the command line. It is by no means even remotely complete but it will give you an impression of the basic structure and concepts, so you can quickly fill in the gaps for your personal use case. The tutorial starts with setting up your account and forges a bridge from requesting a Spot instance, over exchanging files with it, hooking up additional storage, to finally terminating it. I am not though explaining interaction with the AWS web console – we’ll only resort it for some initial configuration. As usual the target audience are Linux users but the AWS CLI tools are pretty much identical for Windows.
First of all …
… get yourself an AWS account at aws.amazon.com, enter the AWS console and switch to the “Security Credentials” section (see drop-down menu under your name on the right side in the bar at the top). There you create yourself a new user and you grant it full access to EC2 and S3 by attaching the policies “AmazonEC2FullAccess” and “AmazonS3FullAccess”. Also create for that user Access Keys and store its ID and the Secret Key somewhere (we’ll need it soon). Furthermore create yourself in the EC2 section under “Network & Security” / “Key pairs” a new key pair named “aws-test” and store the private key on your computer as ~/.ssh/aws-test.pem. Finally you’re ready to go.
Setting up AWS CLI
1 2 3 4 5 6 7 8 9 10 11 12 |
# installing AWS CLI sudo apt-get install awscli # configuring AWSCLI # 1. enter your Access Key ID # 2. enter your Secret Access Key # 3. choose region close to you [*] (f.x. "eu-west-1") # 4. enter "text" aws configure # restrict access permissions - otherwise ssh will complain chmod 400 ~/.ssh/aws-test.pem |
[*]: AWS regions and availability zones
Spot vs On-Demand Instances
At AWS you can either request an On-Demand instance or a Spot instance. For On-Demand you pay the regular price and for a Spot instance you enter a bid – if your bid exceeds the Spot price you get your instance – if the Spot price suddenly exceeds your bid then your instance gets automatically terminated. We’ll request a m3.medium Spot instance.
Let’s have a look at the bidding history for a m3.medium Linux/UNIX machine in the eu-west-1 region:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
> aws ec2 describe-spot-price-history --start-time $(date -u +"%Y%m%dT%H0000") --product "Linux/UNIX" --instance-type "m3.medium" --region eu-west-1 --output table ------------------------------------------------------------------------------------------------------- | DescribeSpotPriceHistory | +-----------------------------------------------------------------------------------------------------+ || SpotPriceHistory || |+------------------+---------------+---------------------+------------+-----------------------------+| || AvailabilityZone | InstanceType | ProductDescription | SpotPrice | Timestamp || |+------------------+---------------+---------------------+------------+-----------------------------+| || eu-west-1c | m3.medium | Linux/UNIX | 0.010300 | 2015-04-21T12:41:46.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010400 | 2015-04-21T12:35:08.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010300 | 2015-04-21T12:28:30.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010400 | 2015-04-21T12:25:12.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010300 | 2015-04-21T12:21:54.000Z || || eu-west-1a | m3.medium | Linux/UNIX | 0.010300 | 2015-04-21T12:15:18.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010400 | 2015-04-21T12:07:00.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010300 | 2015-04-21T12:00:18.000Z || || eu-west-1c | m3.medium | Linux/UNIX | 0.010400 | 2015-04-21T11:58:39.000Z || || eu-west-1a | m3.medium | Linux/UNIX | 0.010200 | 2015-04-21T11:33:48.000Z || || eu-west-1b | m3.medium | Linux/UNIX | 0.010100 | 2015-04-20T14:44:53.000Z || |+------------------+---------------+---------------------+------------+-----------------------------+| |
For a regular Irish m3.medium Linux On-Demand instance we would pay (at the time of writing) $0.077. The spot price history indicates that we can get away with about $0.02 for a stable and soon available m3.medium instance.
A Few Notes on the Command Above
The CLI command structure is aws [options] <command> <subcommand> [parameters] . If you need help on the aws CLI type aws help , if you need guidance on aws ec2 go aws ec2 help and if you are in need for instructions regarding aws ec2 describe-spot-price-history then aws ec2 describe-spot-price-history help is your friend. You get the idea.
--region and --output are available for most of the aws commands. --region allows you to override the default region (which you set with aws configure). --output may be text, json or table. In case you want to pipe the table into a less or a file then you might have to switch the coloring off ( --color off).
The commands in this tutorial will not work if just copy-pasted due to the newlines, which would have to be escaped by appending a backslash at the end. I chose not to do that for the sake of readability.
Creating a Security Group
Let’s assume we not just want to connect to the instance via SSH but also intend to run some HTTP server on port 5000. For that we need a custom security group which specifies which ports are open for what IPs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# set MYIP to your external IP address MYIP=$(curl -s http://myip.dnsomatic.com | grep -P '[\d.]') # create a new security group and save its returned ID to SGID SGID=$(aws ec2 create-security-group --group-name aws-test --description "test security group" --region eu-west-1) # allow your IP to access port 5000 aws ec2 authorize-security-group-ingress --group-name digits --protocol tcp --port 5000 --cidr $MYIP/32 --region eu-west-1 # allow your IP to access port 22 (SSH) aws ec2 authorize-security-group-ingress --group-name digits --protocol tcp --port 22 --cidr $MYIP/32 --region eu-west-1 |
Requesting a Spot Instance
For the Spot instance we are going to load a Ubuntu 14.04 64bit image (AMI).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# okay, I cheated here ... this ID I figured out from the # list of suggested AMIs when you intend to launch an instance # from the AWS web console ;) IMGID_UBUNTU="ami-47a23a30" aws ec2 request-spot-instances --region eu-west-1 --spot-price 0.02 --launch-specification "{ \"KeyName\": \"aws-test\", \"ImageId\": \"$IMGID_UBUNTU\", \"InstanceType\": \"m3.medium\" , \"SecurityGroupIds\": [\"$SGID\"] }" |
To keep an eye on your pending Spot instance requests you can periodically check the status with watch (leave with Ctrl+C):
1 2 3 4 5 6 7 8 |
> watch -n 1 "aws ec2 describe-spot-instance-requests --region eu-west-1" SPOTINSTANCEREQUESTS 2015-04-22T09:47:17.000Z i-8eceeb68 eu-west-1a Linux/UNIX sir-01p5wnj8 0.020000 active one-time LAUNCHSPECIFICATION ami-47a23a30 m3.medium aws subnet-b4ab8cf2 MONITORING False PLACEMENT eu-west-1a SECURITYGROUPS sg-f5f61290 default STATUS fulfilled Your Spot request is fulfilled. 2015-04-22T09:50:33.000Z |
Connecting to the Instance
If you don’t know what tmux is, I highly recommend you check it out. It is indispensable for efficiently working via a terminal. It allows you to keep a session on a remote computer open and what’s even more important to segment one terminal window into windows and panes – so you can work comfortably in multiple terminal sessions.
Before we can connect we need the public domain name of the instance – not sure if this is the most beautiful method, but it works:
1 2 3 4 |
> aws ec2 describe-instances --region eu-west-1 --output json | grep PublicDnsName | head -n 1 "PublicDnsName": "ec2-52-17-148-167.eu-west-1.compute.amazonaws.com", |
With the EC2 instance up and running, its domain at hand and the keys available – we are ready to connect:
1 2 3 |
ssh ~/.ssh/aws-test.pem ubuntu@ec2-52-17-148-167.eu-west-1.compute.amazonaws.com # to exit the session enter "exit" |
As soon as you’re on the instance it is a good idea to upgrade the software.
1 2 |
sudo apt-get update sudo apt-get dist-upgrade |
Pump up the Volume
The instance comes by default with 8GB of disk space. Maybe that is not enough or you would like to have an external volume for your data which you can attach and detach to instances as needed. Especially b/c the data on your instance is gone if you terminate it (you could create a new image though – see below). For that purpose you can request an almost arbitrarily large EBS (Elastic Block Store) volume. Let’s request a 100 GB volume EBS volume of type “gp2”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# availability zones available in our region > aws ec2 describe-availability-zones --region eu-west-1 AVAILABILITYZONES eu-west-1 available eu-west-1a AVAILABILITYZONES eu-west-1 available eu-west-1b AVAILABILITYZONES eu-west-1 available eu-west-1c # create the 100 GB volume of type gp2 in any of the available zones > aws ec2 create-volume --size 100 --availability-zone eu-west-1a --volume-type gp2 --region eu-west-1 eu-west-1a 2015-04-22T14:25:54.715Z False 300 100 None creating vol-83ba419c gp2 # what was our instance's ID again? > aws ec2 describe-instances --region eu-west-1 --output json | grep InstanceId "InstanceId": "i-8eceeb68", # let's attach the volume to the instance > aws ec2 attach-volume --volume-id vol-83ba419c --instance-id i-8eceeb68 --device /dev/xvdf --region eu-west-1 2015-04-22T14:27:48.288Z /dev/xvdf i-8eceeb68 attaching vol-83ba419c |
At this time the volume is likely to be available already, but will just be registered as an available storage device. To use and access it we’ll have to format and mount it first.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# there it is (right at the bottom) $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvda 202:0 0 8G 0 disk `-xvda1 202:1 0 8G 0 part / xvdb 202:16 0 4G 0 disk /mnt xvdf 202:80 0 100G 0 disk # is it formatted already? no. $ sudo file -s /dev/xvdf /dev/xvdf: data # then let's format it $ sudo mkfs -t ext4 /dev/xvdf mke2fs 1.42.9 (4-Feb-2014) Filesystem label= OS type: Linux Block size=4096 (log=2) ... Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done # we need a directory for mounting $mkdir volume # and now we can mount the volume $ sudo mount /dev/xvdf ~/volume # owner of the volume is root now - let's make it ubuntu sudo chown ubuntu:ubuntu volume -R |
Some instance types come with additional available – yet ephemeral (i.e. it’s gone after termination) – storage. m3.medium for example comes along with (meager) 4GB of free space. This volume (named xvdb ) is currently mounted at /mnt as you can see from the output of lsblk above.
Exchanging Data between the Local Computer and the EC2 Instance
Now let’s assume we have a file on our local computer at ~/file-local and a file on the just attached volume of the remote instance at ~/volume/file-ec2.
1 2 3 4 5 6 7 8 9 10 11 |
# uploading ~/file-local > scp -i ~/.ssh/aws-test.pem ~/file-local ubuntu@ec2-52-17-148-167.eu-west-1.compute.amazonaws.com:/home/ubuntu/volume file-local 100% 0 0.0KB/s 00:00 # downloading file-ec2 to /~ > scp -i ~/.ssh/aws-test.pem ubuntu@ec2-52-17-148-167.eu-west-1.compute.amazonaws.com:/home/ubuntu/volume/file-ec2 ~/ file-ec2 100% 0 0.0KB/s 00:00 |
Preserve State as Image
Maybe you invested considerable effort into the setup of your instance and you would like to start out at where you finished this time. Then you should create an instance capturing the state of your instance.
1 2 3 4 5 |
aws ec2 create-image --instance-id i-8eceeb68 --name my-image --description "my image is so great" --region eu-west-1 |
Detach Volume and Terminate Instance
Let’s call it a day – so we’ll detach the volume and terminate the instance.
1 2 3 4 5 |
aws ec3 detach-volume --volume-id vol-83ba419c aws ec3 terminate-instances --instance-ids i-8eceeb68 |
Enough for today – have fun with your rentable data center!
(original article published on www.joyofdata.de)
Typo in the last code block: “ec3”. ;-)