Using Ruby to configure EC2 instances: a lesson learned
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…