Thursday, August 26, 2010

Using BoxGrinder meta-appliance to create custom EC2 AMIs

While I'm happy with BoxGrinder, I don't use it on a daily basis and keep forgetting the trivial instructions; so instead of stressing the project mantainers with the same questions I'll write the instructions here as a reference for myself and a tutorial for whoever might be interested.

What is BoxGrinder?
It's a Ruby tool which creates virtual machines from simple definition files; these Appliance Definition files are cloud-vendor and virtualization tecnology neutral, so you define your appliance once and with different plugins you have them running on different virtualization platforms. So while I'm experimenting my builds with Amazon's EC2, I know I'll be able to provide the same appliance to VMWare systems, VirtualBox, KVM, even create bootable USB keys.

It currently supports Fedora, Red Hat, CentOS operating systems and built images can be run on several targets; it also uploads the built image, in my case using EC2 it will register the new AMI for me.

For a complete introduction, there's a nice video on the official website.

Following instructions are collected from the official documentation which you can find here, I only cherry-picked what I'm interested in for my own goals, so make sure to look at the full documentation in case you need more options or target different virtualization providers.

Meta-Appliance
A meta-appliance is an appliance containing almost all what we need to build other appliances; so instead of installing all of the needed software locally, you can grab one from EC2's AMI catalogue and use it. I like this option as you'll end up having to upload your AMI to S3, so if you assemble it directly on Amazon's systems this process will be way quicker and spare your bandwith.
When selecting a meta-appliance, make sure you select the appropriate architecture: as of BoxGrinder 0.5.1 you need a 64bit meta-appliance to build 64bit AMIs, or a 32bit meta-appliance to build a 23bit AMI (this last limitation will likely be resolved soon as BGBUILD-46).

There we go:
start an instance of ami-96db30ff and connect with your private key using SSH.

Then update the system, and install some tools:

yum update
rpm -Uvh http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm
yum install createrepo subversion
gem install boxgrinder-build boxgrinder-build-ec2-platform-plugin boxgrinder-build-s3-delivery-plugin boxgrinder-build-fedora-os-plugin

Ec2-ami-tools is a requirement to bundle the AMIs on S3, createrepo is useful to integrate own-built RPMs, and finally I use subversion to manage the appliance definition files.

Now create some directories and the local RPM repositories:

mkdir -p /opt/repo/RPMS/i386 /opt/repo/RPMS/noarch /opt/repo/RPMS/x86_64 ~/.boxgrinder/plugins
createrepo /opt/repo/RPMS/i386 && createrepo /opt/repo/RPMS/x86_64 && createrepo /opt/repo/RPMS/noarch

Enter S3 credentials in the plugin configuration to be able to upload your AMI:


vi ~/.boxgrinder/plugins/s3

The configuration looks like this, just omitting the passwords:

access_key: xx
secret_access_key: xxx
bucket: scarlet-private-amis
account_number: 3441-4397-4060
cert_file: /root/cert.pem
key_file: /root/soseaws.pem

You have to upload the cert.pem and soseaws.pem files, these are your private keys for accessing all of AWS services.
Now get the appliance definitions:

svn co https://dev.sourcesense.com/repos/dev/scarlet/trunk/appliance-build/appliances appliances --no-auth-cache --username s.grinovero

And create an AMI:

boxgrinder-build appliances/common-scarlet.appl -p ec2 -d ami

This will end as:

I, [2010-08-26T09:14:52.070877 #18565] INFO -- : Bundling AMI...
I, [2010-08-26T09:16:44.546519 #18565] INFO -- : Bundling AMI finished.
I, [2010-08-26T09:16:44.547023 #18565] INFO -- : Uploading common-scarlet AMI to bucket 'scarlet-private-amis'...
I, [2010-08-26T09:17:43.906981 #18565] INFO -- : Image successfully registered under id: ami-723ed41b.

Done! Now take a note of the registered AMI id and use it to start N-copies of it.

Appliance Definition files
Again, to see all the options read the Stormgrind documentation, anyway an appliance definition looks like:

Example definition

name: common-scarlet
summary: Base AMI definition common to all scarlet AMIs
version: 2
release: 1
os:
  name: fedora
  version: "13"
  password: xxx
hardware:
  cpus: 2
  memory: 512
  partitions:
    /:
      size: 3
packages:
  includes:
    - bash
    - yum
    - vim-minimal
    - openssh-server
    - chkconfig
    - acpid
    - dhclient
    - openssh-clients
    - mc
    - subversion
    - mutt
    - rsync
    - s3cmd
repos:
  - name: "local-noarch"
    baseurl: "file:///opt/repo/RPMS/noarch"
    ephemeral: true
  - name: "local-#ARCH#"
    baseurl: "file:///opt/repo/RPMS/#ARCH#"
    ephemeral: true

Note the pointers to the local RPM repository, there you can add RPM packages which you want to be included in the built appliance, in my case my own application which is not available in the default Fedora repositories.

Hudson Definition
to have a nice Fedora 13 with all latest updates running latest Hudson, just have BoxGrinder grind this definition:

name: hudson-scarlet
summary: Hudson instance to run builds of Scarlet
version: 2
release: 1
os:
  name: fedora
  version: 13
  password: yyy
hardware:
  cpus: 2
  memory: 512
  partitions:
    /:
      size: 3
    /var/lib/hudson/:
      size: 50
appliances:
  - common-scarlet
packages:
  includes:
    - hudson
    - java-1.6.0-openjdk
repos:
  - name: "hudson-repo"
    baseurl: "http://hudson-ci.org/redhat/"
post:
  base:
    - "/sbin/chkconfig --level 345 hudson on"

Note the inheritance to the appliance of the previous example: this appliance will contain also the parent's packages, then an additional repository is enabled to download Hudson and a large partitions is dedicated to it.
Finally, a post-build script is started which will make sure Hudson is started, you won't even need to login to the machine to configure it.