Nov 20 2007

RubyWorks Production Stack on Amazon EC2

rubyworks-ec2 automates deploying Ruby On Rails applications to an Amazon Elastic Compute Cloud (EC2) instance using the RubyWorks Production Stack. It is a collection of Capistrano 2.0 recipes and utilities, not an AMI.

Using rubyworks-ec2 will effectively bootstrap a clean Debian Etch AMI, installing the RubyWorks Production Stack, Apache 2, MySQL, utilities and cron jobs for backing up and restoring the database from Amazon S3.

The running stack comprises of Apache 2 serving static content, HAProxy load balancing Mongrels, 4 Mongrel instances, monit monitoring HAProxy, Mongrel and the OS and MySQL with its datadir pointing to the /mnt partition of the AMI.

Deploying to a new AMI instance post first time setup is achieved with 3 commands - cap instance:start, cap instance:bootstrap and cap deploy - or 4, in case there's a need to migrate the database.

Prerequisites

A working Amazon EC2 account, based on the instructions described in the EC2 Getting Started Guide and a working Rails application that's setup to use MySQL in Production mode, has Rails and any required gems unpacked in its vendor directory and is versioned in a Subversion repository.

Getting started

Following the EC2 Getting Started Guide, you should have a directory named .ec2 in your home directory containing a PEM encoded signed X.509 certificate and an unencrypted, PEM encoded RSA private key that corresponds to the X.509 certificate.

You should also have an RSA keypair named something similar to id_rsa-gsg-keypair. Copy this file to the $HOME/.ec2/ directory. If you have the public counterpart to this key - in this case id_rsa-gsg-keypair.pub - copy it to $HOME/.ec2 as well. If you don't, we'll get it once we start the AMI. This step is crucial in order for Capistrano to be able to connect to the instance.

Download the rubyworks-ec2 gem and install it:

sudo gem i rubyworks-ec2-<version>.gem

Invoke capify . from the top directory of the Rails application. This will create two files, Capfile and config/deploy.rb.

Require rubyworks-ec2 in Capfile:

require "rubyworks-ec2"

Next, configure the required deployment properties in config/deploy.rb:

set :instance_id, ""
set :instance_url, ""

set :application, "shotgun_blues"
set :repository, "http://svn.shotgun.com/blues/trunk"

role :app, instance_url
role :web, instance_url
role :db,  instance_url, :primary => true

set :keypair, "gsp-keypair"
set :account_id, "123456789098"
set :access_key_id, "ABCDE123456789"
set :secret_access_key, "323848492AHSBCYEBDNCSCUENCCKS"
set :pk, "pk-323848492AHSBCYEBDNCSCUENCCKS.pem"
set :cert, "cert-323848492AHSBCYEBDNCSCUENCCKS.pem"
set :packages, %w(apache2 subversion mysql-server libmysql-ruby less) # plus any additional packages you'd like to install on the image
set :gems, %w(aws-s3 ezcrypto) #plus any additional gems you'd like to install on the instance

We'll set the instance_id and instance_url properties after we start an instance. The value for the keypair property must be the name of the RSA keypair in $HOME/.ec2. So, if your keypair file is named id_rsa-gsp-keypair, the keypair property value should be gsp-keypair. The account_id, access_key_id and secret_access_key are your AWS ACCOUNT ID, ACCESS KEY ID and SECRET ACCESS KEY. pk and cert are the filenames of the PEM certificate and key in $HOME/.ec2.

If your Subversion repository is using HTTP Basic authentication, add the following two lines in config/deploy.rb:

set :scm_username, 'svnusername'
set :scm_password, 'svnpassword'

Deploy the application

Start a Debian Etch AMI:

cap instance:start

Wait a few moments and invoke ec2-describe-instances. Once your instance has been started, the output of the ec2-describe-instances command will provide the instance id and instance url. Set these values in config/deploy.rb:

set :instance_id, "i-sd92adsd"
set :instance_url, "ec2-67-202-1-72.z-2.compute-1.amazonaws.com"

If you don't have a copy of your public RSA key, invoke:

cap instance:cp_public_key

This will copy you public RSA key from the instance to your $HOME/.ec2 directory.

cap instance:bootstrap

This command will take a while to complete. It effectively installs RubyWorks, the AWS::S3 library, copies your amazon keys, database backup and restore utitilies, installs Apache 2, sets up an Apache virtual host, installs Subversion and MySQL on the instance. It sets up a cron job for backing up the Database on Amazon S3 every 40 minutes and restores the database to the latest version found on S3, if any exist, otherwise creates a database named <application>_production where application is the value of the application property in config/deploy.rb.

After the command completes, you should be able to navigate to the instance's URL from a browser and see the Rails welcome page.

Proceed by invoking cap deploy and, if this is the first time you're deploying your application, you might want to do a cap deploy:migrate.

To perform a remote login to the instance, invoke:

cap instance:ssh

To back up the database to S3:

cap db:backup

To backup the image to S3 (bundle, upload and register), invoke:

cap image:backup

To monitor services running on the instance:

cap monit:status

To stop the instance:

cap instance:stop

Acknowledgments

rubyworks-ec2 uses Paul Morris's public Debian Etch AMI (ami-30f11459).

License

rubyworks-ec2 is copyright © 2007 nutrun.com. rubyworks-ec2 is Open Source Software - LICENSE

RubyWorks and the RubyWorks Production Stack are © ThoughtWorks inc.

Amazon Web Services TM Customer Agreement