Here’s my current recipe for how to build an Ubuntu 9.10 Karmic AMI, either the new EBS boot or the standard S3 based, using the Ubuntu vmbuilder software. The Ubuntu vmbuilder utility replaces ec2ubuntu-build-ami for building EC2 images and it can build images for a number of other virtual machine formats as well.
There is a lot of room for simplification and scripting in the following instructions, but I figured I’d publish what is working now so others can take advantage of the research to date. Happy New Year!
Some sections are marked [For EBS boot AMI] or [For S3 based AMI] and should only be followed when you are building that type of AMI. The rest of the sections apply to either type. It is possible to follow all instructions to build both types of AMIs at the same time.
-
Run an instance of Ubuntu 9.10 Karmic AMI, either 32-bit or 64-bit depending on which architecture AMI you wish to build. I prefer the
c1.*
instance types to speed up the builds, but you can get by cheaper with them1.*
instance types. Make a note of the resulting instance id:# 32-bit instanceid=$(ec2-run-instances \ --key YOURKEYPAIR \ --availability-zone us-east-1a \ --instance-type c1.medium \ ami-1515f67c | egrep ^INSTANCE | cut -f2) echo "instanceid=$instanceid" # 64-bit instanceid=$(ec2-run-instances \ --key YOURKEYPAIR \ --availability-zone us-east-1a \ --instance-type c1.xlarge \ ami-ab15f6c2 | egrep ^INSTANCE | cut -f2) echo "instanceid=$instanceid"
Wait for the instance to move to the “running” state, then note the public hostname:
while host=$(ec2-describe-instances "$instanceid" | egrep ^INSTANCE | cut -f4) && test -z $host; do echo -n .; sleep 1; done echo host=$host
-
Copy your X.509 certificate and private key to the instance. Use the correct locations for your credential files:
rsync \ --rsh="ssh -i YOURKEYPAIR.pem" \ --rsync-path="sudo rsync" \ ~/.ec2/{cert,pk}-*.pem \ ubuntu@$host:/mnt/
-
Connect to the instance:
ssh -i YOURKEYPAIR.pem ubuntu@$host
-
Install the image building software. We install the
python-vm-builder
package from Karmic, but we’re going to be using the latestvmbuilder
from the development branch in Launchpad because it has good bug fixes. We also use the EC2 API tools from the Ubuntu on EC2 ec2-tools PPA because they are more up to date than the ones in Karmic, letting us register EBS boot AMIs:export DEBIAN_FRONTEND=noninteractive echo "deb http://ppa.launchpad.net/ubuntu-on-ec2/ec2-tools/ubuntu karmic main" | sudo tee /etc/apt/sources.list.d/ubuntu-on-ec2-ec2-tools.list && sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9EE6D873 && sudo apt-get update && sudo -E apt-get upgrade -y && sudo -E apt-get install -y \ python-vm-builder ec2-ami-tools ec2-api-tools bzr && bzr branch lp:vmbuilder
You can ignore the “Launchpad ID” warning from bzr.
-
Fill in your AWS credentials:
export AWS_USER_ID=... export AWS_ACCESS_KEY_ID=... export AWS_SECRET_ACCESS_KEY=... export EC2_CERT=$(echo /mnt/cert-*.pem) export EC2_PRIVATE_KEY=$(echo /mnt/pk-*.pem)
Set up parameters and create files to be used by the build process. The bucket value is only required for S3 based AMIs:
bucket=... codename=karmic release=9.10 tag=server if [ $(uname -m) = 'x86_64' ]; then arch=x86_64 arch2=amd64 pkgopts="--addpkg=libc6-i386" kernelopts="--ec2-kernel=aki-fd15f694 --ec2-ramdisk=ari-c515f6ac" ebsopts="--kernel=aki-fd15f694 --ramdisk=ari-c515f6ac" ebsopts="$ebsopts --block-device-mapping /dev/sdb=ephemeral0" else arch=i386 arch2=i386 pkgopts= kernelopts="--ec2-kernel=aki-5f15f636 --ec2-ramdisk=ari-0915f660" ebsopts="--kernel=aki-5f15f636 --ramdisk=ari-0915f660" ebsopts="$ebsopts --block-device-mapping /dev/sda2=ephemeral0" fi cat > part-i386.txt <<EOM root 10240 a1 /mnt 1 a2 swap 1024 a3 EOM cat > part-x86_64.txt <<EOM root 10240 a1 /mnt 1 b EOM
-
Create a script to perform local customizations to the image before it is bundled. This is passed to
vmbuilder
below using the--execscript
option:cat > setup-server <<'EOM' #!/bin/bash -ex imagedir=$1 # fix what I consider to be bugs in vmbuilder perl -pi -e "s%^127.0.1.1.*\n%%" $imagedir/etc/hosts rm -f $imagedir/etc/hostname # Use multiverse perl -pi -e 's%(universe)$%$1 multiverse%' \ $imagedir/etc/ec2-init/templates/sources.list.tmpl # Add Alestic PPA for runurl package (handy in user-data scripts) echo "deb http://ppa.launchpad.net/alestic/ppa/ubuntu karmic main" | tee $imagedir/etc/apt/sources.list.d/alestic-ppa.list chroot $imagedir \ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BE09C571 # Add ubuntu-on-ec2/ec2-tools PPA for updated ec2-ami-tools echo "deb http://ppa.launchpad.net/ubuntu-on-ec2/ec2-tools/ubuntu karmic main" | sudo tee $imagedir/etc/apt/sources.list.d/ubuntu-on-ec2-ec2-tools.list chroot $imagedir \ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9EE6D873 # Install packages chroot $imagedir apt-get update chroot $imagedir apt-get install -y runurl chroot $imagedir apt-get install -y ec2-ami-tools EOM chmod 755 setup-server
-
Build the image:
now=$(date +%Y%m%d-%H%M) dest=/mnt/dest-$codename-$now prefix=ubuntu-$release-$codename-$arch-$tag-$now description="Ubuntu $release $codename $arch $tag $now" sudo vmbuilder/vmbuilder xen ubuntu \ --suite=$codename \ --arch=$arch2 \ --dest=$dest \ --tmp=/mnt \ --ec2 \ --ec2-version="$description" \ --manifest=$prefix.manifest \ --lock-user \ --part=part-$arch.txt \ $kernelopts \ $pkgopts \ --execscript ./setup-server \ --debug
[For S3 based AMI] include the following options in the vmbuilder command above. This does not preclude you from also building an EBS boot AMI with the same image. Make a note of the resulting AMI id output by vmbuilder:
--ec2-bundle \ --ec2-upload \ --ec2-register \ --ec2-bucket=$bucket \ --ec2-prefix=$prefix \ --ec2-user=$AWS_USER_ID \ --ec2-cert=$EC2_CERT \ --ec2-key=$EC2_PRIVATE_KEY \ --ec2-access-key=$AWS_ACCESS_KEY_ID \ --ec2-secret-key=$AWS_SECRET_ACCESS_KEY \
-
[For EBS boot AMI] Copy the image files to a new EBS volume, snapshot it, and register the snapshot as an EBS boot AMI. Make a note of the resulting AMI id:
size=15 # root disk in GB volumeid=$(ec2-create-volume --size $size --availability-zone us-east-1a | cut -f2) instanceid=$(wget -qO- http://instance-data/latest/meta-data/instance-id) ec2-attach-volume --device /dev/sdi --instance "$instanceid" "$volumeid" while [ ! -e /dev/sdi ]; do echo -n .; sleep 1; done sudo mkfs.ext3 -F /dev/sdi ebsimage=$dest/ebs sudo mkdir $ebsimage sudo mount /dev/sdi $ebsimage imageroot=$dest/root sudo mkdir $imageroot sudo mount -oloop $dest/root.img $imageroot sudo tar -cSf - -C $imageroot . | sudo tar xvf - -C $ebsimage sudo umount $imageroot $ebsimage ec2-detach-volume "$volumeid" snapshotid=$(ec2-create-snapshot "$volumeid" | cut -f2) ec2-delete-volume "$volumeid" while ec2-describe-snapshots "$snapshotid" | grep -q pending do echo -n .; sleep 1; done ec2-register \ --architecture $arch \ --name "$prefix" \ --description "$description" \ $ebsopts \ --snapshot "$snapshotid"
-
Depending on what you want to keep from the above process, there are various things that you might want to clean up.
If you no longer want to use an S3 based AMI:
ec2-deregister $amiid ec2-delete-bundle \ --access-key $AWS_ACCESS_KEY_ID \ --secret-key $AWS_SECRET_ACCESS_KEY \ --bucket $bucket \ --prefix $prefix
If you no longer want to use an EBS boot AMI:
ec2-deregister $amiid ec2-delete-snapshot $snapshotid
When you’re done with the original instance:
ec2-terminate-instance $instanceid
In the above instructions I stray a bit from the defaults. For example, I add the runurl package from the Alestic PPA so that it is available for use in user-data scripts on first boot. I enable multiverse
for easy access to more software, and I install ec2-ami-tools
which works better for me than the current euca2ools
.
I also set /mnt
to the first ephemeral store on the instance even on EBS boot AMIs. This more closely matches the default on the S3 based AMIs, but means that /mnt
will not be persistent across a stop/start of an EBS boot instance.
Explore and set options as you see fit for your applications. Go wild with the --execscript
feature (similar to the ec2ubuntu-build-ami --script
option) to customize your image.
The following vmbuilder
options do not currently work with creating EC2 images: --mirror
, --components
, --ppa
. I have submitted bug 502490 to track this.
As with much of my work here, I’m simply explaining how to use software that others have spent a lot of energy building. In this case a lot of thanks go to the Ubuntu server team for developing vmbuilder, the EC2 plugin, the ec2-init startup software, and the code which builds the official Ubuntu AMIs; especially Søren Hansen, Scott Moser, and Chuck Short. I also appreciate the folks who reviewed early copies of these instructions and provided feedback including Scott Moser, Art Zemon, Trifon Trifonov, Vaibhav Puranik, and Chris.
Community feedback, bug reports, and enhancements for these instructions are welcomed.