Also on twitter ( twitter.com/nutrun )

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 ServicesTM Customer Agreement

20 Responses to “RubyWorks Production Stack on Amazon EC2”

  1. Carlos Villela Says:

    This is awesome! Thanks, George! :D

  2. Prasanna Says:

    Just what I needed, just at the right time!

    Thanks George!
    -Prasanna

  3. links for 2007-11-24 Says:

    [...] Nutrun » Blog Archive » RubyWorks Production Stack on Amazon EC2 Web programming, design and Guitar Tone. (tags: aws capistrano deployment ec2 rails ruby) [...]

  4. Shane Vitarana Says:

    Great work! This worked well for me. This project is like deprec for ec2. Any chance of merging in some deprec functionality? Like configuring mongrel in the recipe and setting up multiple apps on an instance?

    In the future it’ll be awesome to see specialized recipes, i.e: one to create a load balancing instance (using HAProxy or Swiftiply), one to create an app server instance, one for master/slave DB’s, etc. Let me know if you need any contributers.

  5. Vysnu &#187; links for&nbsp;2007-11-26 Says:

    [...] Nutrun » Blog Archive » RubyWorks Production Stack on Amazon EC2 (tags: ec2 rubyworks) [...]

  6. Web 2.0 Announcer Says:

    Nutrun » Blog Archive » RubyWorks Production Stack on Amazon EC2…

    [...][...]…

  7. Michael Christenson II Says:

    Finally! I’ve been at it with ec2onrails for days! This seems to work so far. I’m well past the stupid authentication problems I was having with ec2onrails. Cheers!

  8. RamK Says:

    Does this have imagemagick installed in it? Is the imagemagick &gt; 6.3.0 ?

    Thanks

  9. George Malamidis Says:

    No imagemagick or rmagick. In general, installing specific libraries is up to the user.

  10. Interesting Ruby Tidbits That Don&#8217;t Need Separate Posts #11 Says:

    [...] Amazon EC2 (Elastic Compute Cloud) Control Libraryamazon-ec2 is a super slick library that makes it super-easy to control Amazon EC2 instances in Ruby code. It also comes with a special shell &#8220;ec2sh&#8221; that gives you a much nicer (in my opinion) interface to control and manipulate EC2 instances than the usual command line tools provided by Amazon. The documentation for this is superb with examples of using all of the various methods it provides, ec2sh, and examples of EC2 control from Ruby and Rails apps.RubyWorks Production Stack on Amazon EC2Continuing with the Amazon EC2 theme, Nutrun posts about rubyworks-ec2, a set of Capistrano recipes and utilities to deploy the Rubyworks Production Stack (a complete Ruby and Rails stack) on Amazon EC2 instances. The stack includes Apache 2, HAProxy load balancer, Mongrel, monit, and a bunch of other useful tools. If you want a way to get a Rails / Ruby stack running on an EC2 instance in minutes, this is essential reading.Simple Geocoding in RubyThe Cartographer library is an old-time favorite for doing geocoding from Rails applications. A developer with Assay Depot, however, decided that a more direct approach of querying Google for the results was necessary. The result is a 49 line module that can return latitude, longitude, address, street, and other geographical information when provided with, say, a ZIP or a street address.Tutorial for Installing and Configuring Nginx and Rails on UbuntuJames O&#8217;Kelly has put together a comprehensive tutorial going through all of the stages necessary to install and configure Nginx and Rails together to run applications on an Ubuntu server. James&#8217; blog RailsJitsu.com is definitely worth a look (and perhaps to subscribe to!) as he seems to have a knack for regularly putting together good Rails (and especially Mephisto) focused posts.Presentation: Haml and Sass in 15 MinutesHaml is a markup language commonly used by Rails developers that makes it easy to produce well-formatted, valid XHTML in as few lines as possible. Sass is similar, but for CSS (supporting nested rules, referencing parent rules, and lots of other time saving goodness). In &#8220;Haml and Sass in 15 Minutes&#8220;, Patrick Crowley guides us through using these two technologies. [...]

  11. Mike Jones Says:

    Hey George this is awesome, got me up and running in no time at all..
    \m/&gt;_

  12. emil tin Says:

    Hi, this looks great!
    However, when trying to follow your instructions, bootstrapping failed with the error:
    * executing `instance:install_packages’
    /opt/local/lib/ruby/gems/1.8/gems/capistrano-2.1.0/lib/capistrano/configuration/namespaces.rb:187:in `method_missing’: undefined local variable or method `packages’ for # (NameError)

    After looking in the source i figured that I needed to add the following lines to deploy.rb:
    set :packages, %w(apache2 subversion mysql-server libmysql-ruby less)
    set :gems, %w(aws-s3 ezcrypto)

    After that it works. You might include the lines in the instructions on this page. I didn’t use capify because I’m migrating from a previous setup, so I didn’t get the two lines automatically, and was puzzled at first.

  13. emil tin Says:

    I successfully run:

    cap instance:start
    (copy instance id and address to deploy.rb)
    cap deploy
    cap deploy:migrate

    So far so good. But when I point my browser at the server, I’m just redirected to /apache2-default/, and get a white page with the words “It Works!”, nothing else. If I run cap monit:status, I can see that the four mongrels are running. log/production.log is empty except for the line “# Logfile created on Sat Mar 22 12:12:23 +0000 2008″.

    What could be wrong, and how I can fix it? Is there a forum for rubyworks-ec2? Thanks!

  14. emil tin Says:

    (feel free to moderate my flood of comments :-) )

    Ok, the default page i described above was caused by lack of the config/server folder. Some problem as with the package list, I didn’t use capify, so they were never created in my local app folder. Once I got that folder created and added to SVN, things worked much better.

    But now I have a different problem – during bootstrapping, the command ‘etc/init.d/mysql start’ fails:

    **[out :: ...... ] Starting MySQL database server: mysqld . . . . . . . . . . failed!

    Never the less, it seems that mysql is in fact running. If I perform the rest of the tasks (performed by bootstrapping) manually, my app is working fine, and can be viewed in my browser.

  15. George Malamidis Says:

    Emil,

    Thanks for your comments. I’ve updated the article to include the missing “set” directives. I think it’s worthwhile to note that the bootstrap task will not “rollback”, that is, if any of the tasks fail, whichever tasks ran before the failure will still take effect.

  16. Scott Robertson Says:

    When I run instance:bootstrap I receive the following error
    * executing `deploy:setup’
    * executing “umask 02 && mkdir -p /usr/team_maker /usr/team_maker/releases /usr/team_maker/shared /usr/team_maker/shared/system /usr/team_maker/shared/log /usr/team_maker/shared/pids”
    servers: ["ec2-75-101-218-41.compute-1.amazonaws.com"]
    [ec2-75-101-218-41.compute-1.amazonaws.com] executing command
    *** [err :: ec2-75-101-218-41.compute-1.amazonaws.com] sudo: no passwd entry for app!
    command finished
    command “umask 02 && mkdir -p /usr/team_maker /usr/team_maker/releases /usr/team_maker/shared /usr/team_maker/shared/system /usr/team_maker/shared/log /usr/team_maker/shared/pids” failed on ec2-75-101-218-41.compute-1.amazonaws.com

    Poking around in the instance, it seems that there is no ‘app’ user.

  17. Scott Robertson Says:

    I killed the instance and restarted this time with this at the bottom of my Capfile

    set :runner, :root

    Has gotten me past this error. Not sure if deploying this as the root user is the right thing to do or not.

  18. Scott Robertson Says:

    I ran capify but did not get the config/server folder. Poking around in rubyworks svn I found this script, which generated the Capfile,deploy.rb and server

    capify-for-ec2

  19. Bill G. Says:

    This is a great write-up, thanks! It got me close to up-and-running pretty fast. Like commenter #8 above I got hung up on a missing imagemagick install. I can do this manually on the instnace after running cap instance:start, but are there hooks for me to add these steps to my ‘instance:start’ cap target?

    Also I needed to run these commands as well before I could ssh or http to my instance fyi. You might want to add this instruction to the post (or to the gem actually):

    ec2-authorize default -p 22
    ec2-authorize default -p 80

  20. nutrun » Blog Archive » Phusion Passenger on Amazon EC2 Says:

    [...] It is assumed that your environment has been previously configured for launching EC2 AMIs. If not, you might want to read the EC2 Getting Started Guide, or refer to the first bits of this article. [...]

Leave a Reply