• Using Ruby to configure EC2 instances: a lesson learned

    by Ben

    On Tuesday, we had Mike Culver from Amazon give a great talk about Amazon's web services. We had pretty much decided on using AWS for Devver, but Mike's talk convinced us even more.

    So for the past few days we've been porting our code to work with EC2 . We've also been building scripts that will configure the machine instances on boot.

    When you're using EC2, you can store custom machine images, but you really don't really want to be saving a new image for every tweak you make to the machine. It's a lot more flexible to just save a basic image and give the instance a script to run when it boots, like this:

    ec2-run-instances [some-image-name] -f config.rb

    In this example, I'm passing a Ruby script, but you can pass any type of file at all.

    I found a couple of great tutorials, but unfortunately they didn't do quite what I wanted, so I hacked up my own solution. It's just a few lines in the /etc/rc.local file (which runs after the machine boots) that grabs the config.rb file and runs it.

    Unfortunately, for some reason, my Ruby script was not getting run. After a painfully long debugging session, I figured out that the environment had not been configured for RubyGems when my script was run, so my 'require' statements were breaking the code. The key lesson is that no matter what language you're using, /etc/rc.local is running in a different environment than a logged-in user, so environment variables like PATH (and in this case, RUBY_OPT) will not be set up the same way.

    Anyway, here's the code I added to my /etc/rc.local file:

    # AMI configuration code, based on code from
    #http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1085&categoryID=100
    
    # grab the file from Amazon's web service. Yes, this IP address is always the same
    /usr/bin/wget http://169.254.169.254/latest/user-data -O /tmp/payload.rb
    
    # if wget error code is 0, there was no error
    if [ $? -eq 0 ]; then
      if [ -e /tmp/payload.rb ]; then
        # DON'T forget the -rubygems option! You need it if you call 'require' in your config code
        /usr/bin/ruby -rubygems /tmp/payload.rb
      else
        echo "rc.local : No payload.rb script to run"
      fi
    else
      echo "rc.local : error retrieving user data"
    fi

    I hope that helps anyone out there starting to play with EC2...

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on June 6th, 2008 by Ben in Amazon Web Services, Ruby.