Here at Rails Machine, we have written, on occasion, about moonshine, our open source configuration management and deployment system. But now, I’m happy to announce it works with the Rails 3.0.0.beta.
Lots of people have written about getting up and running on Rails 3, or about upgrading from Rails 2 to Rails 3. I’m not going to repeat that here, but here are some links that might interest you:
- rails-upgrade: Automating a portion of the Rails 3 upgrade process
- Live coding Rails 3 upgrade
- Upgrading to Rails 3
Instead, I will focus on getting an existing Rails 3 application deployed. For narrative purposes, I’m going to spin the tale in which I deploy a fictional application.
The background
Here’s a little background you should be aware of before I begin my tale
- I have an application, zomgblog, which works with rails-3.0.0.beta
- I’m hosting the code on GitHub at http://github.com/technicalpickles/zomgblog)
- I have a freshly installed Ubuntu 8.10 server (the version supported by moonshine)
- I have a domain name setup, zomgblog.technicalpickles.com, which points at my freshly setup server
- I have a ‘rails’ user on the server, with my SSH public key setup in
~/.ssh/authorized_keys
for password-less access - I setup sudo to allow ‘rails’ to allow sudo without a password by adding
rails ALL=(ALL) NOPASSWD:ALL
to/etc/sudoers
on the server - I have installed capistrano locally: gem install capistrano
Adding moonshine to my application
I started in my local checkout. First thing I did was install moonshine itself:
rails plugin install git://github.com/railsmachine/moonshine.git
Next, I used the moonshine-provided generator to setup moonshine for my
application. It has a few options, so I reviewed rails generate moonshine--
help
. Ultimately, I decided on:
rails generate moonshine --domain zomgblog.technicalpickles.com --user=rails --repository [email protected]:technicalpickles/zomgblog.git
I don’t plan to deviate from the default moonshine stack, so there’s not much
else to change. I do need to my config/database.yml
for production though.
Moonshine assumes MySQL will be used, and will handle installing it, creating
the database, and running migrations, so I need a production stanza that looks
like:
production:
adapter: mysql
encoding: utf8
reconnect: false
database: zomgblog_production
pool: 5
username: zomgblog
password: zomgsosecretandsecure
socket: /var/run/mysqld/mysqld.sock
I knew my application was working with the gem dependencies I had installed locally. I didn’t want any surprises though, so I should use the same versions on production. bundler made this easy:
bundle lock
Before proceeding, I needed to commit and push the changes:
git add .
git ci -m "Moonshined application and locked dependencies"
git push origin master
The first deploy
At this point, I’m ready to bootstrap my server. This takes about 15 minutes, and will create the minimal environment that moonshine can run in.
cap deploy:setup
I’m ready to deploy when that’s done. Moonshine does a lot of heavy lifting
during deployment which makes sure the server is in compliance with what’s
defined in app/manifests/application_manifest.rb
. Since I didn’t change
anything, I end up with the default stack of Apache, MySQL, and Passenger.
This usually takes about 10 minutes.
cap deploy
I may now rejoice and reap the rewards of a fully deployed Rails 3 application.
Subsequent deploys
Application development, like life, goes on. From now on, I can continue to develop and deploy just like any other Rails application out there
# insert development & testing
git push origin master
cap deploy
In cases of changing dependencies, I need to do a little extra work before deploying because of the way bundler works:
# make changes to Gemfile bundle unlock bundle install bundle lock git add Gemfile Gemfile.lock git ci -m “Updated dependencies” cap deploy
In the case of having to changing the configuration of my server, I don’t even need to ssh there. Moonshine (and the underlying shadow_puppet) provides an automated way to manage it. See the Shadow Puppet overview and examples for more details.
Some caveats with Rails 3 and moonshine
There are a two points worth noting, particularly if you are used to using moonshine with Rails 2.
First, before bundler was introduced, moonshine had it’s own mechanism for installing gems on the server:
- Add dependencies to
config/environment.rb
- Run
rake moonshine:gems
to updateconfig/gems.yml
- Commit
config/gems.yml
.
When deploying, moonshine uses config/gems.yml
to install the gems, in
addition to system dependencies they might need (ie libxml2 for nokogiri).
But now Rails 3 has the bundler, so moonshine will try to use bundler if you have a Gemfile in your application. One side effect of this is that, because of a bug in rubygems-1.3.5, moonshine isn’t able to install system dependencies of gems managed by Gemfile. This is fixed in 1.3.6 when released
The second is that Rails 3 is Rack based, so Passenger’s Rack support is used.
According to the 2.2.9 release notes, Passenger does not support it’s smart
spawn mode for Rack applications yet though. Contrary to some reports,
removing config.ru
will not allow Passenger’s Rails support to be used
instead of its Rack support because removing config.ru
will render your
application unbootable.
Future Moonshine developments
It’s been a long road to Rails 3, and we at Rails Machine fully intend to keep moonshine up and running with it. Don’t worry though: Rails 2 support is not being deprecated.
Supporting Rails 3 does open some interesting doors. In particular, by
supporting bundler, any application with a Gemfile
should benefit from the
improvement. In addition, Rails 3 is a first class Rack citizen, so anytime
there’s a config.ru
file, Passenger will default to it’s Rack mode.
Between bundler support and detecting config.ru
to turn on Passenger’s rack
support, this moves moonshine in the right direction to support any Rack
application in the future, not just Rails.