A FreeBSD AMI Builder AMI

I've been working on the FreeBSD/EC2 platform for a long time; five years ago I finally had it running, and for the past few years it has provided the behaviour FreeBSD users expect — stability and high performance — across all EC2 instance types. Making the platform work was just the first step though; next comes making it usable.

Some people are happy with simply having a virtual machine which runs the base FreeBSD system; for them, the published FreeBSD/EC2 images (which, as of FreeBSD 10.2-RELEASE, are built by the FreeBSD Release Engineer) will be sufficient. For users who want to use "stock" FreeBSD but would like to have some extra setup performed when the instance launches — say, to install some packages, edit some configuration files, and enable some services — I wrote the configinit tool. And for users who need to make changes to FreeBSD itself, I added code for building AMIs into the FreeBSD source tree, so you can take a modified FreeBSD tree and run make ec2ami to generate a reusable image.

There was one group for whom I didn't have a good solution yet, however: Users who want to create FreeBSD AMIs with minor changes, without wanting to go to the effort of performing a complete FreeBSD release build. Ironically, I am exactly such a user: All of the EC2 instances I use for my online backup service make use of spiped to protect sshd and provide encrypted and authenticated tunnels to my mailserver and package server; and so having spiped preinstalled with the appropriate keys would significantly streamline my deployment process. While it's possible to launch a FreeBSD EC2 instance, make some changes, and then ask EC2 to create a new AMI out of it, this rarely produces a "clean" AMI: A lot of code runs when an EC2 instance first launches — creating the ec2-user user, installing the appropriate SSH public key, creating SSH host keys, growing the root filesystem if launched with a larger root disk, downloading and installing updates to FreeBSD, downloading and installing packages... — and much of this needs to be manually reverted before a reusable AMI can be created; not to mention command histories and log files written during the configuration process, which the more fastidious among us may wish to avoid publishing. To solve this problem, I present the FreeBSD AMI Builder, now available as ami-28682f42 in the EC2 US-East-1 region.

Much like my depenguinator, the FreeBSD AMI Builder works by booting a full FreeBSD system into a memory disk; having done that, it no longer needs to access anything on disk, and so it can safely unmount and overwrite the existing on-disk filesystem. A fresh FreeBSD/EC2 image is written onto the disk and then mounted at /mnt, at which point you can SSH into the instance — which, since it is running in a memory disk, can allow you to SSH in without touching the image you're creating — and then make whatever changes you'd like. (The one minor disadvantage to running in a memory disk is that t2.micro instances don't have enough RAM; all the larger instance types work fine, though, and this limitation only applies to the process of building AMIs, not to instances you launch later.)

This becomes even better with a clever feature Amazon added to EC2 a few years ago: IAM Roles. In short, IAM Roles allow you to provide ephemeral AWS keys to an EC2 instance. To make use of this, create an IAM Policy which grants access to the EC2 "CreateImage" API call, and an IAM Role which has that policy attached; then launch the FreeBSD AMI Builder with that Role attached. Now you can run

# mkami "My AMI Name" "My AMI Description"
and through the magic of IAM Roles the EC2 instance will be able to issue the necessary API call to create an AMI out of itself.

For all that the FreeBSD AMI Builder is a useful tool, it also demonstrates what can be done using configinit: I created the AMI by launching a FreeBSD/EC2 instance with this script provided as EC2 user-data. When the instance booted, it fetched the EC2 user-data; identified it as being a shell script and executed it; and that script assembled the disk image required for running the AMI Builder without my ever having to SSH into the instance. In short, that shell script is a FreeBSD AMI Builder AMI Builder.

But wait, there's more! The FreeBSD AMI Builder is itself a FreeBSD/EC2 AMI, so it too has access to configinit. If you set up the aforementioned IAM Role and launch the AMI Builder with this EC2 user-data

#!/bin/sh
export ASSUME_ALWAYS_YES=YES
pkg -r /mnt fetch -d apache24
pkg -c /mnt install apache24
echo apache24_enable=YES >> /mnt/etc/rc.conf
mkami "FreeBSD 10.2 w/ Apache 2.4" "FreeBSD with Apache pre-installed"
shutdown -p now
it will install Apache 2.4, enable it, create a new AMI, and then shut down the AMI Builder instance. (The separate pkg commands for downloading and installing packages are necessary to work around a bug in pkg relating to hard links and alternate roots.) A short time later, and you have an AMI with Apache 2.4 preinstalled and enabled, ready to be launched. Of course in this case you could simply use the "stock" FreeBSD AMI and have Apache installed at boot time using the appropriate EC2 user-data; but a clean and repeatable customized AMI build in less than ten minutes is nonetheless impressive!

One of the difficulties I've encountered in getting people to use FreeBSD on EC2 is that there are very few "customized" FreeBSD/EC2 images available. I know new EC2 users often find preconfigured images very helpful, and once they start out on Linux they tend to stay there. While I see lots of exciting things happening in the FreeBSD community, we're not nearly good enough at showing it off to the rest of the world. This may make that final step a little bit easier.

Finally, if you find this useful, please consider donating to the FreeBSD Foundation. As I write this they're at $481,324 out of a target of $1,250,000 of donations for the year, with less than six weeks left; they really do wonderful work supporting the FreeBSD project and deserve all the support we can offer them.

Posted at 2015-11-21 12:15 | Permanent link | Comments
blog comments powered by Disqus

Recent posts

Monthly Archives

Yearly Archives


RSS