This will guide you though creating a customized AMI on Amazon EC2.
This is mostly for the benefit of those in the class who read this post. I’m writing this mostly as a tutorial instead of a “what I did” because I’m only going to give enough instruction to get something running, not tell you all the tinkering I did. I also apologize for the varying tense of the writing. Some steps got written before and some after I had actually done them.
I’m going to be setting up my server instance using the latest instance from Ubuntu as my starting point. I’ll also go over how I set up my computer, a MacBook Pro running Mac OS X 10.6.6.
For those not in the class, I’m running my instance on the US East Region, so any AMI IDs mentioned refer to that region. And of course, you’ll need to change bucket names and file names if yours are different.
Here’s the specs of my finished AMI:
- Ubuntu 10.10 (Maverick Meerkat) Server 32-bit
- Apache 2.2
- PHP 5.3
- mod_python (just like the TA…just in case)
- Smarty template engine
Before we begin
The first thing I did was create a key pair. You can do this when you set up your first instance, but if you get it out of the way first, it’s easier to get your whole computer setup out of the way. Generate the key pair. We’ll use it pretty soon.
You’ll also need the private key and certificate. You’re not going to get anywhere without these things. Once you’ve got them, we can begin.
I’m using a Mac. I found a great little tutorial that I used to setup my laptop. Here’s the steps I took to setup my laptop with a few, but not all of the commands I used.
- Open up a new terminal window. Create a new directory .ec2:
- Copy the private keys into this directory. Once there, cd into the directory and change the permissions to user readable only:
cd .ec2/ chmod 400 *.pem
- Now download the Amazon EC2 API Tools and copy the bin and lib folders into the .ec2 directory. I guess you don’t need these to start an instance or anything, but they can only make your life easier. I also deleted the cmd files from the bin, this isn’t Windows:
- You’ll have to setup some environment variables in order to use these tools. Open up your bash profile (
vi ~/.profilefor me) and add the following lines:
# Setup Amazon EC2 Command-Line Tools export EC2_HOME=~/.ec2 export PATH=$PATH:$EC2_HOME/bin export EC2_PRIVATE_KEY=$EC2_HOME/PrivateKey.pem export EC2_CERT=$EC2_HOME/X509Cert.pem export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home/
- When you launch your instance, you’ll want to SSH into it, and to help me out, I added these lines to my
Host ec2-* HostName %h.compute-1.amazonaws.com User ubuntu IdentityFile ~/.ec2/personal-key-pair.pem UserKnownHostsFile ~/.ec2/known_hosts StrictHostKeyChecking no
This will allow you to simply type
ssh ec2-##-##-##-## and get into your client.
- Close your terminal. Your bash profile changes won’t take affect until you restart. Restart and execute the command
ec2-describe-instances. You should see a list of the running instances (remember to turn yours off when you’re not using it!).
That’s all you should need to do on your personal machine.
Creating a New AMI
I went into a lot of detail with the computer setup. I’m not going to give a command by command details with setting up an AMI, because that’s the assignment.
Edit: I think I actually did just what I said I wouldn’t…
I started with the latest Ubuntu server image. This is Ubuntu 10.10 (Maverick Meerkat) Server 32-bit. The AMI info page can be found here. I recommend using the listed (at the time of this writing) AMI
There is an updated image available that is not listed on Amazon’s pages (yet) but is listed on the Ubuntu website, but it has one bug that can cause a lot of headaches. The US East AMI ID is
ami-a6f504cf. You can decide if you want to be brave or if you want to be safe.
ec2-bund-vol is broken (kinda)
The latest AMI (
ami-a6f504cf) has a small bug that will prevent it from bundling without using a patched version of
ec2-bund-vol. Read for more information. You can avoid a lot of trouble by using the previous AMI:
ami-1a837773. It should be recent enough that you shouldn’t have to worry.
I found the above information after attempting to bundle about 20 times. I started from a base AMI about 6 times. I was doing everything right, but each time, my newly bundled/uploaded/registered AMI would fail to launch. (I have saved you, my reader, from hours—maybe days—of frustration.)
First thing’s first. In your favorite text editor, open
/etc/apt/sources.list. Uncomment the four lines that end in
multiverse (4th group). This will allow you to do the updates and get the correct software for your distribution.
If you used the latest AMI (
ami-a6f504cf), you’ll need to complete one extra step. If you’re using
ami-1a837773, you can skip ahead.
ami-a6f504cf users, type this:
sudo add-apt-repository ppa:smoser/bundle-fix-sru-test
You’ll then want to update apt. I recommend upgrading everything too:
sudo apt-get update sudo apt-get upgrade
Here’s some the packages you’ll absolutely need or want:
ec2-ami-tools ec2-api-tools apache2 zip
If you’re using PHP, you should install the following packages:
php5 php5-gd php5-curl php5-dev php-pear smarty
If you’ll be using Python (or if you want the option of switching to it if PHP can’t cut it):
libapache2-mod-python python-imaging python-dev python-setuptools python-boto python-cheetah python-simplejson python-pycurl python-gd
Web server configuration
At this point, the easy part is over. Now you need to setup your server to your liking. If you’re picky, this can take a while. I recommend fiddling as little as possible (which, funny enough, was not what I did).
If you installed the apache2 package, it should be running and good to go. the document root is found at
I didn’t have to do anything to get PHP working, though you should make sure
index.php is in the
DirectoryIndex directive in
If you’re using Python, you’ll want follow Steve’s directions. I took his code and put it in
<IfModule mod_python.c> AddHandler mod_python .py PythonHandler mod_python.publisher PythonDebug On </IfModule>
You’ll need to create a symbolic link from
python.conf. Also, edit
dir.conf and add
index.py to your
Tip: mod_python works very differently than PHP. Checkhttp://www.modpython.org/live/current/doc-html/hand-pub.html for some info.
Let’s take this program:
from mod_python import apache def index(req): return "Index" def say(req, what="NOTHING"): return "I am saying %s" % (what,)
If we call this script
index.py and place it in our document root, then going to
/ on our server (in a browser) will display “Index”. Going to
/say will display “I am saying NOTHING”.
/say?what=Hello will display “I am saying Hello”. This page on traversal explains path traversal in more detail.
You should test your Apache configuration at this point. Once you know your configuration is going to work, you’re good. Don’t fiddle too much, or you could be spending 2 hours trying to find a bug that you introduced when you added an extra
/ to a configuration file. (True story.)
Some bloke in class brought up the fact that Ubuntu has a handy feature called
cloud-init.It’s true. So you can just stop worrying your little head about that.
Bundling an AMI
The Amazon EC2 User Guide contains all the instructions for bundling your instance. You can also look on page 226 of Programming Amazon Web Services. Also, you can read this.
You need to prepare for the bundling first. You’ll need:
- The private key pair.
- The certificate file.
- The AWS user id, found in the Account section of the AWS site. Do not include the hyphens in this number.
- Access Key ID and Access Secret Key, also in the account section
Copy all of those files through
scp to your instance. You must move them to
/mnt. Do not leave them in your home folder, as they will be stored in your instance.
You can take the extra effort of truncating apache logs and your bash and vim history if you want. Just in case someone else starts your instance. And you’ve typed anything you don’t want people snooping.
After moving your files over to
/mnt, cd there yourself. Type
ec2-bundle-vol --help to get an idea of the command. I’d make a directory to write the image files too, then type the command:
sudo ec2-bundle-vol -p my-ami.img -d /mnt/bundle/image -r i386 \ -c X509Cert.pem -k PrivateKey.pem -u `cat user_id.txt`
my-ami-img to a prefix with something that identifies you. And change any paths or files names you need. I’ve followed the advice of Programming Amazon Web Services and wrote my image to the bigger
/mnt disk. I also put the user id number into a file
This process will take about 10-20 minutes.
If it takes longer than that, check for a broken pipe (hit enter).
Now you have to upload the AMI to S3 to make it available. I put my access key into the file
access_key.txt and my secret key into
ec2-upload-bundle --help to get an idea of the upload command. Once you’ve done that, you’ll just need to run:
ec2-upload-bundle -m /mnt/bundle/image/my-ami.img.manifest.xml \ -b cs462-machines/my-user-name -a `cat access_key.txt` -s `cat secret_key.txt`
Be sure to change
my-user-name to something more applicable. But this part is important so that the bucket doesn’t get so cluttered. This only takes a minute or two.
Once you’re uploaded, you’re ready to register. If you’ve got the
ec2-api-tools package, you should be able to do this right from your instance. (You can still
apt-get install ec2-api-tools and get them.) Or you can do this part from another machine, use Ruby, or even use the AWS Console.
From your instance, you can type this:
ec2-register -K PrivateKey.pem -C X509Cert.pem \ cs462-machines/your-user-name/my-ami.img.manifest.xml
From your own computer, if you’ve set up your EC2 tools properly, you can type:
This takes only a few seconds, and you should be ready to go.
Test your AMI
Now for the true test. Start up a new instance with your newly bundled AMI. If you’re truly daring, you can stop your previous instance first. But you might want to make sure your instance works and that it will run your user-data as a bootstrap script.
For those of you using PHP, make sure you check out php-aws, because you’re probably going to need it later. I didn’t mention it until now, because I don’t recommend putting it in your PHP globals, so you can package it with the rest of your code. You’ll probably need it locally for reference anyhow.
Because our AWS account has been used for so long and never cleaned out, there’s a lot of garbage in our buckets. Being a fan of the command line, I found this little gem. s3cmd will let you interact with S3 without coding up Ruby or going through the slow web interface. It does have the downside of only being able to delete one object at a time, but it’s probably better that way.
You can use
s3cmd to create small scripts, but you can do the same with Python or Ruby too. But if your favorite language is Bash, this can come in handy.
I want to make you aware of something you should know if you’re going to use EC2 AMIs. When you bundle an AMI, it saves the
authorized_keys files with the bundle. I actually added my own personal public key to my AMI so that I can access it from my laptop or work computer without needing my key-pair on Amazon.
But you should be aware that if you use someone’s AMI, you get whatever they give you. For example, if Bob launches my AMI, I have a back door into the instance. Bob shouldn’t be running my AMI anyway, even if he can (because he’s in my class), so this isn’t a problem. But this is another reason to make sure you use an AMI from a trusted source. (The AMI IDs that I give are from a trusted source.)
After you get the hang of it (or do it 6+ times in 4 days), you’ll see that it’s a pretty simple process. But until you finally start up your customized server, you don’t realized how useful it is. Now I’m able to start up 1 or 100 servers that all have Apache configured the way I want with packages that I find useful. That’s handy.